Skip to main content

Full text of "From the ground up: logic gates et al."

See other formats


"from the ground up" 

logic gates et al. 


Daniele Giacomini appunti2@gmail.com 

1-2013c 



http://archive.org/details/from_the_ground_up 

GNU CC 

GPL FDL BY-SA 








“from the ground up” — Copyright © 2013 Daniele Giacomini 

Via Morganella Est, 21 — 1-31050 Ponzano Veneto (TV) — appunti2@gmail.com 

You can redistribute this work and/or modify it under the terms of the GNU Gen¬ 
eral Public License as published by the Free Software Foundation; either version 3 
of the License, or (at your option) any later version, with the following exceptions 
and clarifications: 

• Quotations and samples of other works are not subject to the scope of the 
license of this work. 

• If you modify this work and/or reuse it partially, under the terms of the license: 
it is your responsibility to avoid misrepresentation of opinion, thought and/or 
feeling of other than you; the notices about changes and the references about 
the original work, must be kept and evidenced conforming to the new work 
characteristics; you may add or remove quotations and/or samples of other 
works; you are required to use a different name for the new work. 

Permission is also granted to copy, distribute and/or modify this work under the 
terms of the GNU Free Documentation License (FDL), either version 1.3 of the 
License, or (at your option) any later version published by the Free Software Foun¬ 
dation (FSF); with no Invariant Sections, with no Front-Cover Text, and with no 
Back-Cover Texts. 

Permission is also granted to copy, distribute and/or modify this work under the 
terms of the Creative Commons Attribution-Share Alike License, version 3.0, as 
published by Creative Commons at http://creativecommons.org/licensesA)y-sa/3. 
0 /. 

This work is distributed in the hope that it will be useful, but WITHOUT ANY 
WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE. 


II 


Table of contents 

Foreword. IV 

Part i Logic circuits. 1 

Traditional logic integrated circuits. 357 

References. 429 

Partii Simple CPU . 431 

References. 1209 

Index . i 


III 









« 


Foreword 


Dear readers, this work is about a collection of notes in the field 
I enjoy to study. I wrote it in English because it is, more or less, 
the conventional language for the information technology; but, at 
the same time, I would like to practice with English as well. How¬ 
ever, even though I might be a good reader in English, I am not yet 
good enough at using it to write: I ask you to forgive me. If you are 
interested in this topic and plan to keep on reading it, I hope you 
will be willing to write me some feedback to correct my usage or 
grammatical errors: I would highly appreciate it. My email address 
is appunti2@gmail.com. 

The book is distributed in different typesetting formats: the main 
PDF version is intended to be read with a small screen device, so the 
characters and the figures (where possible) are bigger than usual, but 
the margins are very narrow. 

Who am I? I was a high school technical teacher. I was thrilled in 
1981 when I first used a Burroughs B91:1 learned to write COBOL 
programs and experienced with other Burroughs proprietary lan¬ 
guages for the system maintenance. Then, I felt excited in 1995 
when I started studying GNU/Linux systems and I dreamed (again) 
a world of free software, free knowledge (and peaceful living); I also 
wrote a book about GNU/Linux and what it could achieve when be¬ 
ing put in good use (of course, I wrote it in Italian, my native lan¬ 
guage). But I found that things did not go as I wished (or dreamed) 
—especially with my teaching experience— because in human na¬ 
ture the ‘freedom’ is something that is not appreciated if it is ‘free’. 

Anyway, I am still attracted by the memory of the passion I had 


IV 



in my young ages, when I imagined that computers could be built 
simply with discrete logic (and all the software could be written from 
scratch)... :-) 

Daniele Giacomini 
Via Morganella Est, 21 
1-31050 Ponzano Veneto (TV) 

Italy 

appunti2 @ gmail.com 

http://itlinkedin.com/pub/daniele-giacomini/4b/364/6b2 

http://www.linkedin.com/in/appunti2/ 


V 


VI 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


Part i 


Logic circuits 

« 

1 Logic functions and logic gates . 7 

1.1 NOT . 9 

1.2 ‘not-inverter’ or ‘buffer’ . 10 

1.3 AND . 11 

1.4 OR . 12 

1.5 XOR . 13 

1.6 Logic networks . 14 

1.7 Operator precedence. 17 

1.8 Irrelevant values inside the truth table. 17 

1.9 Equivalence . 18 

1.10 Sum of products . 22 

1.11 Karnaugh maps . 25 

1.12 Logic gates and multiple lines . 39 

1.13 Electronic logic gates . 41 

1.14 HDL . 45 

2 Introduction to Verilog . 49 

2.1 Minimal notions . 52 

2.2 Hello world! . 52 

2.3 Compiler directives . 58 

2.4 Signal values . 61 

2.5 Literal constants . 61 


1 























2.6 Data types 64 

2.7 Ports . 68 

2.8 Parameters . 70 

2.9 Module declaration . 71 

2.10 Module instance . 73 

2.11 Fully qualified path names . 74 

2.12 Primitives 76 

2.13 Expressions 78 

2.14 Vector and array addressing . 83 

2.15 Strings . 84 

2.16 Functions . 85 

2.17 Netlist modules: combinational circuits . 88 

2.18 Behavioural modules . 95 

2.19 Procedural assignments . 96 

2.20 Blocking delays . 100 

2.21 Wait for a level event . 101 

2.22 Wait for an event expressions . 103 

2.23 Event variables . 105 

2.24 System tasks and functions . 105 

2.25 Control structures . 108 

2.26 Thread control . 110 

3 Combinational circuits . 113 

3.1 Decoder . 119 

3.2 Demultiplexer . 122 

3.3 Multiplexer . 127 

2 



























3.4 Multiplexer and demultiplexer with parallel I/O. 131 

3.5 Binary encoder . 136 

3.6 Priority encoder . 140 

3.7 Logic units . 144 

3.8 Shift and rotation . 146 

3.9 Addition . 154 

3.10 Subtraction . 162 

3.11 Addition and subtraction together. 169 

3.12 Carry lookahead . 173 

3.13 Increment and decrement . 183 

3.14 2’s complement . 189 

3.15 Multiplication. 191 

3.16 Division. 202 

3.17 Magnitude comparator. 206 

4 Arithmetic-logic unit. 211 

4.1 Status flags . 212 

4.2 Size truncation . 216 

4.3 Sign inversion . 219 

4.4 Addition and subtraction . 221 

4.5 Shift and rotation . 223 

4.6 Magnitude comparison . 229 

4.7 Multiplication . 233 

4.8 Division . 239 

4.9 Logic unit . 244 

4.10 Joining all the modules together . 246 

3 



























4.11 Bit sliced ALU . 248 

5 Latch and flip-flop . 257 

5.1 Propagation delay . 258 

5.2 Truth tables. 260 

5.3 SR latch . 261 

5.4 Bounce-free switch . 269 

5.5 Gated SR latches . 271 

5.6 SR flip-flop . 275 

5.7 Time: setup/hold and recovery/removal . 279 

5.8 D latch and D flip-flop . 280 

5.9 T flip-flop . 286 

5.10 JK flip-flop . 288 

5.11 Troublesome JK flip-flops . 291 

6 Registers . 295 

6.1 Multiplexer . 300 

6.2 Simple data register . 301 

6.3 Shift register . 308 

6.4 Asynchronous counter with T flip-flop . 311 

6.5 Synchronous T flip-flop counters . 312 

6.6 Synchronous counters with D flip-flops . 314 

6.7 Synchronous counters with parallel load. 320 

Bus and control unit . 325 

7.1 Tri-state buffer . 325 

7.2 Hardcoded bus control unit. 329 


4 


























7.3 Microcode . 334 

8 TKGate 2 introduction and troubleshooting . 343 

8.1 Modules . 344 

8.2 Module library or cut and paste between files. 347 

8.3 Bit-size . 350 

8.4 Cut and paste troubles . 352 

8.5 File PostScript and EPS . 352 

8.6 Multiplexers, demultiplexers and encoders depiction . 353 

Traditional logic integrated circuits. 357 

Data distributors or demultiplexers. 359 

Data selectors or multiplexers . 372 

Special circuits . 387 

Arithmetic units. 392 

References. 429 


5 















6 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


1 


Chapter 


Logic functions and logic gates 


n not . 9 

1.2 ‘not-inverter’ or ‘buffer’ . 10 

1.3 AND . 11 

1.4 OR . 12 

1.5 XOR . 13 

1.6 Logic networks . 14 

1.7 Operator precedence. 17 

1.8 Irrelevant values inside the truth table . 17 

1.9 Equivalence . 18 

1.10 Sum of products . 22 

1.11 Karnaugh maps . 25 

1.12 Logic gates and multiple lines . 39 

1.13 Electronic logic gates . 41 

1.14 HDL . 45 


active high 14 active low 14 AND 11 assert 14 boolean algebra 18 
buffer 10 De Morgan’s laws 18 discrete logic 41 floating 41 
fundamental product 22 hardware description language 45 HDL 45 
high impedance 41 IC 41 integrated circuit 41 inverter 9 Karnaugh 
map 25 logic circuit 14 logic connective 7 logic gate 7 logic 
network 14 logic operator 7 logic variable 7 negate 14 NOT 9 
not-inverter 10 OR 12 propagation delay 41 reduction 39 signal 14 
sum of products 22 tri-state buffer 41 Verilog 45 XOR 13 Z 41 
















8 


Logic functions and logic gates 


The term logic comes from the philosophy and it is the way by which 
something can be found true or false. The concepts of ‘true’ and 
‘false’ can be considered as the two elementary values of a logic 
variable. There are different ways to represent the values of a logic 
variable and every context might have its own symbology, but when 
using numbers —unless otherwise specified— it is custom to asso¬ 
ciate 1 to ‘true’ and 0 to ‘false’. 

A logic expression , or a logic function , is the expression or the func¬ 
tion that produces a true or false result. The components of a logic 
expression or function are listed below: 

• declarative propositions - propositions that can be found either 
true or false; 

• logic constants - either true or false; 

• logic variables - variables that can represent only the values true 
and false; 

• logic functions and operators - the functions or the operators used 
to connect the other logic components into a more complex func¬ 
tion or expression. 

Logical functions can be represented in different ways, depending 
on the context and on possible typographical limitations. Therefore, 
every time it is necessary to understand which is the adopted symbol¬ 
ogy, taking into account that the representation might change inside 
the same document; for example, the body text explaining a prob¬ 
lem might use one symbology, whereas the pictures might have a 
different and more appropriate one. One particular way to represent 



Logic functions and logic gates 9 

a logic function consists on drawing little boxes, with one or more 
inputs and one single output: these are known as logic gates. 


Table 1.1. Some alternative notations regarding the common 
logic functions, associating the symbology used for the corre¬ 
sponding logic gates. 


• 

a 

a — 

>— a 

© 

NOT a 

a’ -ia 

a 

a — 

a 

(aQb) 

a and b 

a A b 

a-b 

ab 

a — 

b 

3 a-b 

(a(T>) 

a or b 

a vb 

a + b 

a — 

b 

a+b 

(aT)k 

a xor b 

a © b 

a 

b 

^ a © b 


The truth tables are used to define the meaning of logic operators: all 
the values of the input variables are matched with the corresponding 
logic results. 


1.1 NOT 

The NOT function has a single input and produces the logic inver¬ 
sion. That is: if the input is true (1), the output is false (0) and vice 
versa. When the NOT function is represented in the form of a logic 
gate, it is known with the name inverter. 
































10 


Logic functions and logic gates 


Figure 1.2. NOT (inverter). 

input output 

output 

a 

truth table 

The figure above shows that there are two alternative ways to repre¬ 
sent an inverter gate: the first one is the most common. 

1.2 'not-inverter 7 or 'buffer 7 


a 


0 

i 


a 


input 


i 

r\ 


a 



output 


a 


input 


a 


■o 



inverter 


Two consecutive inversions give just the original logic value; that is, 
“NOT (NOT A)” is just the same as “A”. There is a logic gate that is 
known as not-inverter or buffer : it does nothing from the logic point 
of view, but it has some meaning for other problems. 


Figure 1.3. Buffer (not-inverter). 



input output 



truth table 


not-inverter 





















Logic functions and logic gates 


11 


From the example shown for the inverter and the buffer logic gates, 
it should be noticed the use of the little bubble that means logic 
inversion. This bubble can appear at the input or at the output and 
it might be used also with other logic gates. 


1.3 AND 


The AND function takes two inputs and the result is true only if both 
inputs are true, otherwise the result is false. 


Figure 1.4. AND. 


input output 


a 

b 

a • b 

0 

0 

0 

0 

1 

0 

1 

0 

0 

1 

1 

1 


truth table 


input 



output 


a • b 


The AND logic function might have more than two input variables 
and the result is true only if all the inputs are also true. The same 
way, the AND logic gate might have more than two input lines, as it 
is shown in the following figure. 











12 


Logic functions and logic gates 


Figure 1.5. Two ways to represent the AND gate with more than 
two inputs. 



1.4 OR 


The OR logic function takes two inputs and the result is true if at 
least one input is true, otherwise the result is false. 


Figure 1.6. OR. 


input output 


a 

b 

a + b 

0 

0 

0 

0 

1 

1 

1 

0 

1 

1 

1 

1 


input 



output 


a + b 


truth table 

The OR logic function might have more than two input variables and 
the result is true if at least one input is also true. The same way, the 
OR logic gate might have more than two input lines, as it is shown 
in the following figure. 


















CT*P 


Logic functions and logic gates 


13 


Figure 1.7. Two ways to represent the OR gate with more than 
two inputs. 



1.5 XOR 


The XOR logic function (<exclusive or) is derived from the other 
ones: it takes two inputs and the result is true if only one input is 
true, otherwise the result is false. 


Figure 1.8. XOR. 


input output 


a 

b 

a©b 

0 

0 

0 

0 

1 

1 

1 

0 

1 

1 

1 

0 


truth table 


input 



output 


a © b 


Even the XOR logic function might have more than two input vari¬ 
ables and the result is true if the true input variables are an odd quan- 



















14 


Logic functions and logic gates 


tity. The same way, the XOR logic gate might have more than two 
input lines, as it is shown in the following figure. 


Figure 1.9. XOR gate with more than two inputs. 



1.6 Logic networks 


Elementary logic functions can be used together to build more com¬ 
plex ones. When using logic gates, connecting two or more gates 
results into a logic network or logic circuit , which are equivalent 
definitions of the same thing. 












Logic functions and logic gates 


15 


Figure 1.10. A simple logic network. 




1 


logic network 


W 


l 


2 





w 


2 




truth table 


logic function 

f= (. x i+ x 2 ).x 2 


1 

X 

2 

f( x r x i) 

0 

0 

0 

0 

1 

0 

1 

0 

1 

1 

1 

0 


The logic gates are connected together with wires; the figure above 
shows a name for every wire, where X\ and x 2 are the inputs of the 
overall logic function and / is the output. Each wire can carry a 
signal of 0 or 1 that in electronics is usually represented by a ten¬ 
sion, measured in Volts and known also as voltage (but even a cur¬ 
rent might be used in a particular technology, to distinguish 0 and 1 
values). In electronic circuits there is usually a common connection 
known as ground , because it carries the 0-volt point of reference for 
the other electric tensions. In a logic circuit, when a wire has the 
same voltage of the ground, it represents the value 0; when the elec¬ 
tric tension is higher (or lower, depending on the specific technology 
used) the value that a wire represents is 1. 


Together with the truth table, a logic network might have also a tim¬ 
ing diagram, where the electric signals are shown dynamically, like 
the example below: when the line of the diagram is low it represents 
the value 0; when the line is high it represents the value 1. 




16 


Logic functions and logic gates 


Figure 1.11. Timing diagram. 






w 


w 


f 


1 

o 

i 

0 

1 

0 

1 

0 

1 

0 


time 


The electric signal used to represent the value 1 might be positive or 
negative in relation to the ground potential. The choice to be positive 
or negative depends on the technology used to build the logic gates. 
When a timing diagram is drawn, the value of the signal used to 
represent 1 is always shown high, regardless if it is a positive or 
negative value. 


Figure 1.12. The simple logic network with a negated wire name. 


X 


l 



W 


l 


X 

2 




X 

2 

When a wire is named, this name might be negated. The figure above 
shows the same simple logic network, where the previous wire w 2 is 
replaced by the name x 2 . In fact, the wire x 2 is obtained inverting the 
value at the wire x 2 and so it is easier to read the logic network. 























































































Logic functions and logic gates 


17 


It is common to use the word ‘active’ to mean 1 on a wire, but when 
a wire is labeled with a negated name, the meaning of ‘active’ be¬ 
comes ambiguous. The name of the wire implies the name of the 
signal it carries: a plain name (without negation) means that this is 
the name of the high signal or the name of the value 1 (active high); 
on the other hand, a negated name is the name of a low signal or the 
name of a value 0 (active low). To express the meaning that the sig¬ 
nal is the one that it is expected to be, based on the name of the wire, 
it is custom to use the words assert and negate. For example, in the 
above figure, the wire w \ is asserted when it is high —or one— and 
negated when it is low —or zero—, whereas the wire x 2 is asserted 
when it is low —or zero— and it is negated when it is high —or 
one—. 

1.7 Operator precedence 

When the logic functions are written in the form of expressions, it 
is important to define the order of precedence, to avoid an excessive 
use of parentheses. This order is: NOT, AND, OR. For example, 
a+b c means exactly a+(b-(c)). It should be noticed that it works 
like the usual arithmetic, where multiplication has the precedence 
on the addition. 

The precedence problem is not related to logic networks, because 
the connections define the order of evaluation. 


It is not specified the precedence order for the XOR operator, be¬ 
cause it is a derived function of the other ones. So, if ambiguity 
might occur with a logic expression, parentheses should be used. 










18 Logic functions and logic gates 

1.8 Irrelevant values inside the truth table 


There are situations where truth tables of logic functions can be re¬ 
duced, because for some conditions the value of some inputs are 
irrelevant. When an input value might be anything, it is used a letter 
‘X’. For example, the simple function shown on a previous section 
is (xi+x 2 )*X 2 and it happens that if X\ is 0, it does not matter which 
value has x 2 , because the output remains 0. 


Figure 1.13. Truth table simplified. 


f= (-V X 2 )- X 2 


V 

1 

X 

2 

f( x r x 2 ) 

0 

0 

0 

0 

1 

0 

i 

0 

1 

i 

1 

0 



X 

i 

X 

2 

f( X !> V 

0 

X 

0 

1 

0 

1 

1 

1 

0 


1.9 Equivalence 


Through the elementary logic operators it is possible to build com¬ 
plex functions, where there are different alternatives to obtain the 
same result. For example, the XOR function might be obtained as 
( a+b) (a+b ) or as ( a+b)(ab ) or as ( a+b) (a+b ), or even more 
complex and less useful ways. To transform a logic function into 
another, producing the same result, come to help the De Morgan’s 
laws: 








Logic functions and logic gates 


19 


a • b=(a+b) 



a • b 


b -0 (a+b) 


a+b= (a-b) 



a 

b 


^)o— (a • b) 


Putting together the truth tables of the basic logic functions with the 
De Morgan’s laws, it is possible to find the equivalences shown in 
the following table; equivalences on which is based all the ‘logic’ 
algebra, better known as the boolean algebra (or Boole’s algebra). 


Table 1.15. Boolean algebra equivalences. 


( 1 ) 

a+ 0 = a 

( 2 ) 

O 

II 

o 

• 

( 3 ) 

a+\ = 1 

( 4 ) 

a- 1 = a 

( 5 ) 

a+a = a 

( 6 ) 

a a = a 

( 7 ) 

a+a = 1 

( 8 ) 

a a = 0 

( 9 ) 

a+b — b+a 

( 10 ) 

ab = ba 

( 11 ) 

a+(b+c ) = ( a+b)+c 

( 12 ) 

a(bc) = (ab)c 

( 13 ) 

a(b+c ) = ab+ac 

( 14 ) 

a+b'C — (a+b)'(a+c) 

( 15 ) 

(a+b) = ab 

( 16 ) 

(ab) = a+b 

( 17 ) 

(a) = a 




1. a+0 = a 



2 . a -0 = 0 



3 . a +-1 — 1 







20 


Logic functions and logic gates 


t=r>i 

4. al = a 

cl _ N 

i-D- 1 


5. a+a = a 



6. aa = a 



7. a+a = 1 



8. aa = 0 

•Tj^sD-o 


9. ci-\-b — b+a 



10. a b = b a 




11. #+(Z^+c) — (#+Z>)+c 



a+(b+c) 



(a+b)+c 


12. a (b e) = (a-fc)-c 




(a-b)-c 


O cT P o a" P3 







Logic functions and logic gates 


21 


13. a(b+c ) = ab+ac 




a-b+a-c 


14. a+bc = ( a+b)(a+c) 



(a+b)-(a+c) 


15. ( a+b ) = ab 





a — 

>°ir 

^ - - 





a ' 

b i 

j ^)o — (a+b) 

b — 

>^ L 

J a-b 

a —O 

b —o 

)- 

a-b 

16. 

(ab) = a+b 








a 

b 


a — 


_ _ 





^)o — (a-b) 

b — 


J) — a + b 

a —o' 

b ~°i 

) > 

a + b 

17. 

(a) ■■ 

= a 








a-[ 


- a 

a o^>o — a 

a — 

+> 

— a 


When the logic function is defined using only the basic logic oper¬ 
ators (NOT, AND, OR), the De Morgan’s laws allow to transform 
easily a logic function into its complement. Given the function / it 
is possible to obtain the negated function / following a simple pro¬ 
cedure: 

• the original AND operators are replaced with OR operators and 
vice versa, using parentheses to keep the original evaluation order 
unchanged; 

• all the variables are complemented (negated) with the NOT oper¬ 
ator. 




Logic functions and logic gates 


22 

Example: 

/ = a+bc+d^e+gh 


Please notice that A B is not the same as ( AB ). So, writing AB 
might create confusion, because the line above seems to be unique. 


1.10 Sum of products 

A logic function is an expression made of logic variables, logic con¬ 
stants and logic operators, which produces a logic result (true or 
false). However, a logic function can be described simply with the 
truth table that combines the input variable values with the expected 
result for every input combination. 

Having a truth table it is possible to synthesize the corresponding 
logic function through the method known as the sum of products. 
The sum of products is the ‘sum’ (logic OR) of all the fundamental 
products that describe every input condition. The following picture 
shows three truth tables with two, three and four inputs; for every 
input combinations it is written the fundamental product, which is a 
function that becomes true only with a particular combination. For 
example, the fundamental product A B C (or ABC) describes the 
combination A =0, B =1 and C=0. 





Logic functions and logic gates 


23 


Table 1.16. Fundamental products of functions having two, three 
and four input variables. 


A 

B 

fundamental 

product 

0 

0 

AB 

0 

1 

A B 

1 

0 

AB 

1 

1 

AB 


A 

B 

c 

D 

fundamental 

product 

0 

0 

0 

0 

A 

B 

C 

D 

0 

0 

0 

1 

A 

B 

C 

D 

0 

0 

1 

0 

A 

B 

C 

D 

0 

0 

1 

1 

A 

B 

C 

D 

0 

1 

0 

0 

A 

B 

C 

D 

0 

1 

0 

1 

A 

B 

C 

D 

0 

1 

1 

0 

A 

B 

C 

D 

0 

1 

1 

1 

A 

B 

C 

D 


A 

B 

c 

fundamental 

product 

0 

0 

0 

A 

B 

C 

0 

0 

1 

A 

B 

C 

0 

1 

0 

A 

B 

C 

0 

1 

1 

A 

B 

C 

1 

0 

0 

A 

B 

C 

1 

0 

1 

A 

B 

C 

1 

1 

0 

A 

B 

C 

1 

1 

1 

A 

B 

C 


A 

B 

c 

D 

fundamental 

product 

1 

0 

0 

0 

A 

B 

C 

D 

1 

0 

0 

1 

A 

B 

C 

D 

1 

0 

1 

0 

A 

B 

C 

D 

1 

0 

1 

1 

A 

B 

C 

D 

1 

1 

0 

0 

A 

B 

C 

D 

1 

1 

0 

1 

A 

B 

C 

D 

1 

1 

1 

0 

A 

B 

C 

D 

1 

1 

1 

1 

A 

B 

C 

D 


For example, the function known as NXOR (function of two input 
variables that is true only when the inputs have the same value) is 
synthesized with the procedure that is shown by the following figure. 



24 


Logic functions and logic gates 


Figure 1.17. NXOR function synthesis, starting from the truth 
table. 


A 

B 

fundamental 

product 

function 

result 

normal 

synthesis 

reversed 

synthesis 

0 

0 

A B 

1 

-> AB 


0 

1 

A B 

0 


->AB 

1 

0 

A B 

0 


->A B 

1 

1 

A B 

1 

-► A B 

i 


j (a B + A B ) 
AB+AB \ 

sum of products 



AB+AB 


A 

B 


(a b 


+ 


A B ) 


To synthesize a function, the fundamental products corresponding 
to the expected true combinations are added together (sum of prod¬ 
ucts); as the figure shows, it is also possible to do the opposite to 
obtain the equivalent negated function. 




























Logic functions and logic gates 


25 


1.11 Karnaugh maps 

A logic function can be translated into a Karnaugh map, which can 
help to simplify the expression that synthesize the function. The 
Karnaugh map is a bidimensional representation of the fundamen¬ 
tal products, from the truth table that is to be analyzed. In the fol¬ 
lowing figures are shown three empty maps, for functions with two, 
three and four input variables: care must be taken to the fundamental 
products sequence, because it does not correspond to the one used 
for the truth table. 

Figure 1.18. Karnaugh maps containing the fundamental product 

definitions pertaining to each cell. 


A 

B 

fundamental 

product 

0 

0 

AB 

0 

1 

AB 

1 

0 

AB 

1 

1 

AB 


\ B B 

X AB Xb 


A AB AB 


A 

B 

c 

fundamental 

product 

0 

0 

0 

A 

B 

C 

0 

0 

1 

A 

B 

C 

0 

1 

0 

A 

B 

C 

0 

1 

1 

A 

B 

C 

1 

0 

0 

A 

B 

C 

1 

0 

1 

A 

B 

C 

1 

1 

0 

A 

B 

C 

1 

1 

1 

A 

B 

C 


\ 

C 

C 

AB 

ABC 

ABC 

Xb 

ABC 

ABC 

AB 

ABC 

ABC 

AB 

ABC 

ABC 












Logic functions and logic gates 


26 


A 

B 

c 

D 

fundamental 

product 

0 

0 

0 

0 

A B 

C 

D 

0 

0 

0 

1 

A B 

C 

D 

0 

0 

1 

0 

A B 

c 

D 

0 

0 

1 

1 

A B 

c 

D 

0 

1 

0 

0 

A B 

c 

D 

0 

1 

0 

1 

A B 

c 

D 

0 

1 

1 

0 

A B 

c 

D 

0 

1 

1 

1 

A B 

c 

D 

1 

0 

0 

0 

A B 

c 

D 

1 

0 

0 

1 

A B 

c 

D 

1 

0 

1 

0 

A B 

c 

D 

1 

0 

1 

1 

A B 

c 

D 

1 

1 

0 

0 

A B 

c 

D 

1 

1 

0 

1 

A B 

c 

D 

1 

1 

1 

0 

A B 

c 

D 

1 

1 

1 

1 

A B 

c 

D 



The maps should be used placing inside the cells a 1 where the fun 
damental products are valid. The following figures show some ex 
amples, matching each truth tables with the corresponding map. 





Logic functions and logic gates 

Figure 1.19. Truth tables and Karnaugh maps pairs 
A B I * -i-. I \ 


ABC 


0 0 0 
0 0 1 
0 1 0 
0 1 1 
1 0 0 
1 0 1 
1 1 0 
1 1 1 


0 0 

1 

0 1 

0 

1 0 

0 

1 1 

1 

v B - 

B 

1 

0 

0 

1 



A B C D 

0 0 0 0 
0 0 0 1 
0 0 10 
0 0 11 


1 0 
1 0 
1 0 


1 1 
1 1 


0 10 0 
0 10 1 
0 110 
0 111 
10 0 0 
10 0 1 
10 10 
10 11 
110 0 
110 1 
1110 
1111 


AB 


AB 


AB 


AB 


1 

1 

0 

0 

1 

1 

1 

0 

1 

0 

0 

1 

1 

0 

0 

1 








28 


Logic functions and logic gates 


Once the map is prepared, the cells containing the value 1 should be 
grouped together in rectangular shapes, considering different group¬ 
ing alternatives if possible. Please notice that these groups can be 
only of one, two, four, eight,... elements. 

Figure 1.20. Karnaugh maps with the cells grouped horizontally 
and vertically; the map with four input variables shows two al¬ 
ternative groupings. 


A 

A 


A B 




0 0 

1 

ABC 

\ 

0 1 

0 

0 0 0 

\ 

1 _ 

1 0 

0 

0 0 1 

1 AB 

1 1 

1 

0 1 0 

0 _ 



0 1 1 

0 AB 

V B 

B 

1 0 0 

1 

a 

0 

1 0 1 

1 AB 



1 1 0 

1 — 

0 

0 

1 1 1 

o AB 



A 

B 

c 

D 


0 

0 

0 

0 

1 

0 

0 

0 

1 

1 

0 

0 

1 

0 

0 

0 

0 

1 

1 

0 

0 

1 

0 

0 

1 

0 

1 

0 

1 

1 

0 

1 

1 

0 

0 

0 

1 

1 

1 

1 


A 

B 

c 

D 


1 

0 

0 

0 

1 

1 

0 

0 

1 

0 

1 

0 

1 

0 

1 

1 

0 

1 

1 

0 

1 

1 

0 

0 

1 

1 

1 

0 

1 

0 

1 

1 

1 

0 

1 

1 

1 

1 

1 

0 


















Logic functions and logic gates 


29 



When two adjacent cells —vertically or horizontally— contain the 
value 1, one of the variable regarding the two cells is useless. The 
following figure demonstrates intuitively the process. 




































30 


Logic functions and logic gates 


Figure 1.21. Simplification when two adjacent cells have the 
value 1. 


A B 

\ B B 

0 0 

0 1 

1 0 

1 1 

1 

i A 

0 

0 A 

1 1 

0 0 


AB + AB = A(B + B) = A1 = A 



A -L 


B >-i=5]"^> r 

5 

A > 











































Logic functions and logic gates 


31 


A B 

\ 

B 

B 

0 0 

0 1 

0 

1 A 

0 

1 

1 0 

1 1 

0 

1 

0 

1 


AB+AB =(A + A)B = B • 1 = B 



A > 


B >-1 

B >- 

D>^ 


The simplification comes out from the fact that x OR x is always 
true; therefore, when a rectangular group shows that the same vari¬ 
able appears both normal and negated, that variable can be simply 
ignored. 


Figure 1.22. Example of a map that can not be simplified. 


A 

B 


0 

0 

1 

0 

1 

0 

1 

0 

0 

1 

1 

1 



A B 

A B 



AB+AB 




















































32 


Logic functions and logic gates 


Figure 1.23. Example with three variables. 


A 

B 

c 


0 

0 

0 

1 

0 

0 

1 

1 

0 

1 

0 

0 

0 

1 

1 

0 

1 

0 

0 

1 

1 

0 

1 

1 

1 

1 

0 

1 

1 

1 

1 

0 


AB C + AB C = AC 



ABC + ABC + ABC + ABC = B 


Y Y 

B +AC 













Logic functions and logic gates 


33 


Figure 1.24. Example of alternative simplifications with a map 
having four variables. 


A 

B 

c 

D 


A 

B 

c 

D 


0 

0 

0 

0 

1 

1 

0 

0 

0 

1 

0 

0 

0 

1 

1 

1 

0 

0 

1 

0 

0 

0 

1 

0 

0 

1 

0 

1 

0 

1 

0 

0 

1 

1 

0 

1 

0 

1 

1 

0 

0 

1 

0 

0 

1 

1 

1 

0 

0 

1 

0 

1 

0 

1 

1 

1 

1 

0 

1 

0 

0 

1 

1 

0 

0 

1 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

0 






34 


Logic functions and logic gates 



AC +ABD+ AD 




















Logic functions and logic gates 


35 



CD 

BD 

CD 

BCD= CD 


ACD + ABD + ACD + CD 

Karnaugh maps allow to simplify a logic function with no more than 
four variables, otherwise the map should have more than two dimen¬ 
sions and it would be impractical to view. 

It might happen that the function output for some input combination 
is unspecified, because it doesn’t matter what it is. When it hap¬ 
pens, the synthesis can decide what value is better for the purpose 
of reducing the final expression. That is: the decision, whether these 
values should be grouped or not, is free. 




















36 


Logic functions and logic gates 


Figure 1.25. Example of alternative options when simplifying a 
function with some unspecified output values. 


A 

B 

c 

D 


0 

0 

0 

0 

1 

0 

0 

0 

1 

X 

0 

0 

1 

0 

0 

0 

0 

1 

1 

X 

0 

1 

0 

0 

1 

0 

1 

0 

1 

1 

0 

1 

1 

0 

X 

0 

1 

1 

1 

X 


A 

B 

c 

D 


1 

0 

0 

0 

X 

1 

0 

0 

1 

0 

1 

0 

1 

0 

X 

1 

0 

1 

1 

0 

1 

1 

0 

0 

X 

1 

1 

0 

1 

1 

1 

1 

1 

0 

X 

1 

1 

1 

1 

1 




B+ACD 


















Logic functions and logic gates 


37 




AC + AB 




BC+ACD 


Karnaugh maps can be used also for logic networks with more than 
one output for the same inputs; in that case, these networks are seen 
as multiple logic functions sharing the same input variables: it is 
probably useful to try to share also some more elements inside the 
two functions as it is shown in the following example. 



















38 


Logic functions and logic gates 


Figure 1.26. Two functions of the same input variables, synthe¬ 
sized with two maps. 


A 

B 

c 

/a 

fb 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

0 

1 

0 

0 

0 

0 

1 

1 

1 

1 

1 

0 

0 

0 

0 

1 

0 

1 

0 

0 

1 

1 

0 

1 

0 

1 

1 

1 

1 

0 























Logic functions and logic gates 


39 


Figure 1.27. Logic network solution: first divided and then joined 
(saving a logic gate). 



A> 

B > 
C> 



- 3 > 


1.12 Logic gates and multiple lines 



Designing a complex network it is possible to draw multiple lines 
together if the connected logic is replicated for each one. 


Figure 1.28. Quad inverter. 



The above example shows four inverters designed in parallel, using 
on the left a compact way, where the four input and output lines are 
joined together in a single multiple one. The following figure shows 
a similar parallel connection with four AND gates. 



















































































40 


Logic functions and logic gates 


Figure 1.29. Quad AND. 



The following figure shows a different kind of line joining, related 
to multiple input gates: the OR gate has four input lines, but on the 
left the four lines are joined in a single multiple one: this is known 
as reduction. 

Figure 1.30. Four input OR. 



A parallel gate connection might require that some ports be con¬ 
nected together to a single line. The following figure shows four 
XOR gates with one of the two input ports connected to the same 
line. 







































































Logic functions and logic gates 


41 


Figure 1.31. Quad XOR with a common input line. 


4 





f)C> 

<i=E> 

^)E> 

t)C> 


1.13 Electronic logic gates 


4 


7 




The logic gates are usually implemented inside integrated circuits 
(IC), with various technologies and densities. During the 1970s it 
was commonly used the so called discrete logic , made of small inte¬ 
grated circuits with few logic gates or simple specific logic circuits. 
The old ‘discrete logic’ might give the idea of what can be concretely 
a logic gate in reality. 


Figure 1.32. Four NAND gates inside an integrated circuit. The 
schematic on the left shows that the connections 7 and 14 must 
be used for the power supply: Vcc/Vdd and GND (ground). 



for ‘true’, ‘false’ and ‘unspecified’ (unknown). The electronic logic 
adds another state: ‘Z’ for ‘high impedance’ or ‘floating’. 

















































































































42 


Logic functions and logic gates 


Figure 1.33. Tri-state buffer with an ‘active high’ enable line. 



Figure 1.34. Tri-state buffer with an ‘active low’ enable line. 



The tri-state buffer, shown above, works like a buffer, replicating the 
same value received from the input to the output, but only when the 
enable input is asserted, otherwise its output becomes virtually ‘dis¬ 
connected’. The state of isolation that the tri-state buffer can have 
on the output, when the enable input is negated, is called ‘high 
impedance’ or ‘floating’ and it is used the letter ‘Z’ to show it. 



Logic functions and logic gates 


43 


Figure 1.35. The connection of many output lines together is pos¬ 
sible with tri-state buffers. 


NEVER DO THIS! 



The figure above shows that it is not possible to connect together the 
output of two or more common logic gates, because it is not specified 
what should happen if these outputs drive a different logic state and 
because these components would be likely damaged. On the right 
the circuit is modified with the addition of tri-state buffers; this time 
the connection is possible, but only under a strict condition: only 
one tri-state buffer can be enabled at the same time. But if no one of 
the four tri-state buffers is enabled, the last AND gate on the right 
receives an unpredictable or confused input, corresponding to the Z 
































































Logic functions and logic gates 


44 


state, which is neither 0 nor 1. 

Electronic gates have also another important characteristic: the prop¬ 
agation delay , which means that the gates output is always updated 
with a little delay, compared to the input changes. 


Figure 1.36. Delay introduced by a simple inverter gate. 



in 


out 


2 ns 


time 


The figure above shows that even the simplest component, like the 
inverter gate, introduces a little delay. In that case it appear a delay 
of 2 ns. The following figure shows that the delay can be used to 
produce a short pulse. 








Logic functions and logic gates 


45 


Figure 1.37. Pulse signal produced with an inverter delay. 



in 


in 


out 



n 


n 


n 


n 



a 

>4 


C 

K 


a inverter delay 
b AND gate delay 
c impulse 


It should be noticed that the above example is not practical, because 
the delay is too short to be useful; a longer delay with a sequence of 
more inverters might solve the problem. 


1.14 HDL 


Logic networks can be simply designed in a way that allows humans 
to read them. But when a logic network is to be treated as data, it 
should be ‘designed’ adding all the information needed and not just 
only the graphical aspect, whereas the graphical aspect might also 
be unnecessary and omitted. There are specific languages —just like 
the common programming languages— used to describe the logic 
networks and, more generally, the hardware. These are known as 
hardware description languages and the abbreviation HDL is com¬ 
monly used. 



























































46 


Logic functions and logic gates 


There are two main HDL languages: VHDL and Verilog. Here is 
used Verilog because of its closeness to the C language, allowing 
to show examples without a previous detailed study of the language 
itself. 


As a first example of Verilog coding it is shown how a simple AND 
gate could be synthesized. Verilog defines modules that are intended 
like black boxes with input and output ports; these modules are de¬ 
clared like they were functions. Here the module is declared with the 
name my_and , because the name ‘and’ is obviously reserved. 


Figure 1.38. The module my_and that is to be synthesized with 
Verilog. 


A > 
B > 


my_and 



Y 


The first solution in Verilog code is very simple and it uses a ‘con¬ 
tinuous assignment’ with a little delay (6 ns) to reproduce the prop¬ 
agation delay that real gates have. 


Listing 1.39. Verilog code implementing the my_and module 
with a continuous assignment. 

'timescale Ins 
module my_and (Y, A, B) ; 
input A, B; 
output Y; 

assign #6 Y = A & B; // continuous assignment 

















Logic functions and logic gates 


47 


endmodule 


A very simple variation of the above example consists on the use of 
a gate instantiation, which is named AO ; like the previous example 
it is specified a 6 ns delay. 


Listing 1.40. Verilog code implementing the my_and module 
with a gate instantiation. 


'timescale Ins 


module my_and (Y, A, B); 


input A, B; 


output Y; 


and #6 AO (Y, A, B) ; 

// gate instantiation 

endmodule 



The two example above declare the module my_and and they spec¬ 
ify that A and B are input ports (wires), whereas Y is an output port. 
Then, on the first example it is assigned to the Y wire the result of 
A B, with a 6 ns delay, whereas on the second example it is used 
a gate instantiation with the same delay. Please notice that the con¬ 
tinuous assignment of the first example and the gate instance of the 
second one just work continuously: every time that A or B change 
value, after the specified delay, they update the value assigned to Y. 

A more complex solution might requires to use a memory, defining 
that the output line is the output of a virtual register with the same 
name. This virtual register works like a local variable of a single bit. 




48 


Logic functions and logic gates 


Listing 1.41. Verilog code implementing the my_and module 
with a propagation delay of 6 ns. 


'timescale Ins 


module my_and (Y, A, 

B) ; 

input A, B; 


output Y; 


reg Y; 

// virtual register 

always @(A or B) 

// do if A or B change value 

begin 


# 6; 

// propagation delay 

Y = A & B; 

// assign the result to Y 

end 


endmodule 



The above code, after the module port declarations, specifies that 
the Y wire comes from a register, so that the value of Y should be 
changed assigning something to it (inside a block). Then it starts a 
block delimited by the keywords begin and end, which is executed 
every time that at least one of the input ports (A and B ) changes its 
value. This block starts with a 6 ns pause, then the bitwise A B is 
calculated and assigned to Y. 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


49 


Chapter 


Introduction to Verilog 

2.1 Minimal notions . 52 

2.2 Hello world! . 52 

2.3 Compiler directives . 58 

2.4 Signal values . 61 

2.5 Literal constants . 61 

2.6 Data types 64 

2.7 Ports . 68 

2.8 Parameters . 70 

2.9 Module declaration . 71 

2.10 Module instance . 73 

2.11 Fully qualified path names . 74 

2.12 Primitives 76 

2.13 Expressions 78 

2.14 Vector and array addressing . 83 

2.15 Strings . 84 

2.16 Functions . 85 

2.17 Netlist modules: combinational circuits . 88 

2.18 Behavioural modules . 95 

2.19 Procedural as signments . 96 

2.20 Blocking delays . 100 






















50 Introduction to Verilog 

2.21 Wait for a level event . 101 

2.22 Wait for an event expressions . 103 

2.23 Event variables . 105 

2.24 System tasks and functions . 105 

2.25 Control structures . 108 

2.26 Thread control . 110 


74 ! 78 ! = 78 ! == 78 * 78 */ 52 + 78 . 52 / 78 /* 52 // 52 ; 
52 == 78 === 78 ? : 78 addressing 83 always 95 and 76 array 
64 83 assign 88 assignment 96 begin 95 behavioural module 95 
bit range 83 bit size 64 83 blocking assignment 96buf76bufif0 
76 bufif 1 76 case 108 casex 108 casez 108 combinational 
circuit 88 control structure 108 data type 64 defparam 73 delay 
100 directive 58 end 95 endmodule 71 event 64 105 event 
expression 103 expression 78 floating point number 61 for 108 
forever 108 fork 110 function 85 gate instance 76 HDL 49 if 
108 initial 95 inout 68 input 68 integer 64 integer 
number 61 join 110 level event 101 literal constant 61 macro 58 
memory 64 module 71 module instance 73 nand76 net 64 netlist 
module 88 non-blocking assignment 96 nor 76 not 76 not if 0 
76 notif 1 76 nxor 76 or 76 output 68 parameter 70 port 
68 primitive 76 primitive instance 76 procedural assignment 96 
real 64 reg 64 repeat 108 scalar 64 signal 61 string 61 84 
supplyO 64 supplyl 64 switch instance 76 symbolic macro 58 
system function 105 system task 105 thread 95 thread 110 time 
64 top level module 71 tri 64 triO 64 tril 64 triand64 
trior 64 variable 64 vector 64 83 Verilog 49 wait () 101 
wand 64 while 108 wire 64 wor 64 x 61 xor 76 z 61 & 78 && 








Introduction to Verilog 


51 


78 @ 103 A 78 ~ 78 78 ~ A 78 ~ | 78 | 78 I I 78 { { } } 78 {, } 

78 $display() 52 105 $finish 105 $finish() 52 
$monitor () 105 $time 105 - 78 <78 <= 78 << 78 <<< 78 > 
78 >= 78 >> 78 >>> 78 % 78 'define 58 'else 58 'endif 58 
'ifdef 58 'ifndef 58 'timescale 58 


Logic networks can be simply designed in a way that can be read by 
human. When a logic network is to be treated as data, it should be 
‘designed’ adding all the information needed and not just only the 
graphical aspect, whereas the graphical aspect might also be unnec¬ 
essary and omitted. There are specific languages (just like the com¬ 
mon programming languages) used to describe the logic networks 
and, more generally, the hardware. These are known as hardware 
description languages and the abbreviation HDL is commonly used. 
There are two main HDL languages: VHDL and Verilog. Verilog has 
the advantage to be more terse and similar to the C language. 

When an HDL language is used, the project usually has two pur¬ 
poses: simulation and synthesis. Simulation is used to verify the 
project with a software tool; synthesis is made to obtain some spe¬ 
cific code for programmable hardware or to produce a final inte¬ 
grated circuit. When using an HDL language, some code might have 
specific meaning for the simulation that the synthesis phase might 
ignore. 

To verify the examples of this chapter, the TKGate and Icarus sim¬ 
ulation environments might be used (http://www.tkgate.org , http:// 
iverilog.icarus.com ). 


52 

2.1 Minimal notions 


Introduction to Verilog 


There is some similarity between Verilog and the C language, but 
Verilog is not C and the resemblance is limited to some aesthetics. 
The first minimal notions to start reading the Verilog code are the 
following: 

• comments are the same as C (/*...*/ and //); 

• white spaces are ignored unless they are delimited as string con¬ 
stants; 

• the semicolon (;) is used to terminate the statements and the 
comma (,) is used to separate elements inside a list; 

• identifiers (the names used to identify components defined inside 
the code) are case sensitive and should start with a letter or the 
underscore (_) and might contain letters, digits, underscore (_) 
and dollar ($);* 

• all Verilog keywords are lowercase. 

2.2 Hello world! 

A first minimal program is useful to test the simulation environment. 
The Verilog language includes some functions and instructions, the 
name of which starts with dollar ($). These functions and instruc¬ 
tions are intended to control the simulation environment. The typical 
simulation environment should have the ability to display some text 
that Verilog can output with the $display () function, which works 
in a similar way to the printf () found in C. 


Introduction to Verilog 


53 


Listing 2.1. Two times “Hello world!”. 

module hello; 
initial 
begin 

$display ("Hello world!"); 
$display ("Hello world!"); 
#10 $finish; 
end 

endmodule 


The example listed above shows two times the text “Hello world!”, 
then it waits 10 time units and then it stops the simulation with the 
$finish instruction. Please notice that the $display() function 
adds a new-line at the end of the string and the double display is 
intended to show this feature. It is supposed that the file containing 
the above listing is named ‘hello.v’; to run TKGate with it, the 
following command might be used: 


$ tkgate20 hello.v [Enter] 





54 


Introduction to Verilog 


Figure 2.2. TKGate after the program end. 



The above example might be also compiled and tested with 
Icarus Verilog in the following way: 

$ iverilog -o hello, wp hello.v [Enter] 

The above command generates the file ‘hello. wp’ that can be ex¬ 
ecuted by the command wp: 

$ wp hello .wp [Enter] 

Hello World! 

Hello World! 













































Introduction to Verilog 


55 


This video shows how to replicate the above example, with TKGate 
and with Icarus Verilog, starting from the same source ‘hello . v’: 
ogv http://www.youtube.com/watch?v=kGofhPGWErc . 

To use a Verilog simulation environment it is also necessary to be 
able to trace a wave at some point, to see dynamically what happens 
inside some virtual wires. The next example is made to generate 
two different clock signals at the variables x and y (these variables 
represent a wire with memory and it doesn’t matter how it should be 
implemented). 

Listing 2.4. Two different clock signals. 

module wave; 
reg x; 
reg y; 
initial 
begin 

$dumpfile ("wave.vcd"); 

$dumpvars (0, wave); 

x = 0; 

Y = 0; 
end 
always 
begin 
# 20 ; 
x = 1; 

# 20 ; 
x = 0; 
end 
always 



56 


Introduction to Verilog 


begin 

# 15; 

Y = i; 

# 15; 

Y = 0; 
end 

endmodule 


The above listing contains two simulation functions necessary to 
Icarus Verilog to create the ‘wave.vcd’ with all the variables vari¬ 
ations; this file is then read by GTKwave. The following command 
assumes that the above listing is contained inside the file ‘wave. v’: 

$ iverilog -o wave.vvp wave.v[£«ter] 

$ vvp wave.wp[f«fcr] 

The simulation does not stop by itself and it is necessary to send an 
interruption signal with the keyboard combination [Ctrl c J. 

$ [ Ctrl c ] 

Then vvp turns to work in interactive mode and it is necessary to 
type the command finish: 

> finish [Enter] 

At this point there is the file ‘wave.vcd’ and it can be read with 
GTKwave: 


$ gtkwave wave.vcd [Enter] 





Introduction to Verilog 


57 


Figure 2.5. GTKWave with the variable x and y selected. 


File Edit Search Time Markers View Help 




Q <4 From:|0 sec To:|21950320 s gj Marker: - | Cursor: 5452375 sec 


Signals 

Time 

' 

X 


m 




M H [ 


SST 


Type Signals 


reg x 


reg y 


Filter: 


Append Insert Replace 





±j 


The picture above shows GTKWave with the variables x and y al¬ 
ready selected. To do so, on the left, the module name (wave) must 
be selected, then the variable names appear just below: the variable 
names must be dragged and dropped into the black window that 
should show the waves. 


TKGate can use the same source example, but it does not know the 
functions $dumpfile() and $dumpvars (), so these lines must be re¬ 
moved or commented. 


$ tkgate20 wa ve .v [Enter] 

The following picture shows TKGate running the simulation with a 
‘scope’ window displaying the waves, selected from the net list on 
the left. 










































58 


Introduction to Verilog 


Figure 2.6. GTKWave with the variable x and y selected. 



This video shows how to replicate the above example, with Icarus 
Verilog and TKGate, starting from the same source ‘wave. v ogv 
http://www.youtube.com/watch?v=NLzcXuadiIQ . 


2.3 Compiler directives 


The C language has a pre-compiler that looks for directives like 
#define and #ifdef . The Verilog language has similar directives 
that starts with the character ' (back quote). Like in the C language, 
the compiler directives do not have the final semicolon. 

Like in the C language there is a 'define directive to declare a 
symbolic macro: 


'define macro replacingJext 























































Introduction to Verilog 59 

For example, the symbolic macro 'MY_MACRO representing the value 
45 could be declared as: 

'define MY_MACRO 45 

To use the symbolic macro inside an expression, the ' prefix must 
be included, like this: 

x = a + 'MY_MACRO; 

Like in the C language there are the directives 'ifdef, 'ifndef, 
'else and 'endif, to conditionally select the Verilog code. 


'ifdef macro 

code_if_macro_exists 

'else 

alternative _c ode 

'endif 


'ifndef macro 

code_if_macro_does_not_exist 

'else 

alternative_code 

'endif 


See the following example: 






60 


Introduction to Verilog 


'ifdef MY_MACRO 

x = a + 'MY_MACRO; 

'else 
x = a; 

'endif 

In the above example, the variable x is the sum of a and the macro 
'MY_MACRO, but only if the macro itself is already declared. The next 
example is just the opposite, but with the same meaning: 


'ifndef MY_MACRO 
x = a; 

'else 

x = a + 'MY_MACRO; 

'endif 

The Verilog language requires the definition of the timescale , which 
is the time unit used for the simulation. The timescale is defined with 
the 'timescale directive: 


'timescale integer_delay_unit [ / max resolution ] 

The integer delay unit time and the max resolution are specified with 
values that should be 1, 10 or 100 followed by “s” (seconds), “ms” 
(milliseconds), “us” (microseconds), “ns” (nanoseconds), “ps” (pi¬ 
coseconds) or “fs” (femtoseconds). 


'timescale lOns/lns 

The above example requires that the simulation is made with a preci¬ 
sion of 1 ns, whereas the integer delays are 10 ns multiples, but this 






Introduction to Verilog 


61 


means that a delay of 1 is 10 ns long and a decimal delay time can 
be specified, up to the first decimal position. For example, a delay 
of 1.3 is equal to 13 ns, but 1.35 is also equal to 13 ns, because the 
minimal resolution is of 1 ns. The following example specifies that 
only integer delays notations are allowed (1 ns): 


'timescale Ins 

2.4 Signal values 

Verilog consider four ‘logical’ states: 0,1, unknown and floating (hi- 
impedance). The states 0 and 1 are the well defined logic values; if 
the logic value is unknown or it is not possible to establish it, the 
symbol x or x can be used to express it. If a wire becomes isolated 
from the other connections, the symbol z, z or ? can be used to 
describe it. 


0 

logical 0 

X 

x unknown or unspecified 

1 

logical 1 

z 

z ? floating (high impedance) 


2.5 Literal constants 

A literal constant is a constant value represented directly by its 
value. There are three types of literal constants that Verilog can ex¬ 
pect: integer numbers, floating point numbers and strings. 

The literal constant representing an integer number inside Verilog is 
much different from the common programming languages, because 
it can contain the bit-range, or size: 2 







62 


Introduction to Verilog 


[ [ size ] ' base 

value 


[ [size] ' b 

0 

d | h] value 


The base is a letter specifying the base in which the following num¬ 
ber is represented, but it is always preceded by an apostrophe. The 
allowed bases are: ' b, binary; ' o, octal;' d, decimal; ' h, hexadeci¬ 
mal. Here are some examples with size and base specified: 

1'632 - 7-bit 32io 
7'd232 - 7-bit 104i 0 3 
15'h3B4F - 15-bit 3B4Fi6 
5'blllOl - 5-bit 11101 2 

If the size of the value is not specified, a default size is used, but it 
depends on the implementation and it should be at least of 32 bits 
(although it is not guaranteed). Here are some more examples with¬ 
out size specification: 

' d32 - 32io 
' d232 — 232io 
' h3B4F - 3B4Fi 6 
'blllOl - IIIOI 2 

If even the base is not specified, it is intended to be a decimal value. 

A literal constant can contain some underscore characters, which are 
ignored, because they are useful only to separate the digits for some 






Introduction to Verilog 

aesthetical reasons: 


63 


16'b0101_0100_1110_1011 — 0101010011101011 2 

The integer representation shown above is related to unsigned num¬ 
bers, which might be extended as positive numbers. The current Ver¬ 
ilog standard allows also to specify signed numbers, but the handling 
of signed numbers is not simple and it is useful to avoid it in the be¬ 
ginning. 

When the base is not decimal, the number can contain also unknown 
or floating values, but these particular values are extended if not all 
the requested bits are specified: 

16'hlx2x - 0001xxxx0010xxxx 2 
16 ' hx2x - xxxxxxxx0010xxxx 2 
8' blOzzlO — 0010zzl0 2 
8' bzzlO - zzzzzzl0 2 

A floating point literal constant is represented as a decimal value 
with decimal point; for example: 0.123, 1.23, 12.34. It is the im¬ 
plementation that decides in which way it is encoded internally and 
the bit size that it should have. 

Strings are represented in double quotes. Each character inside the 
string occupies 8 bits and it is encoded following the ASCII stan¬ 
dard. For example: a string made of three characters requires 24 bits. 
Strings can contain a subset of the C language escape sequences: \n, 
\t, \\, \" and \ooo (the last escape sequence is a character defined 
by the octal code). 



64 

2.6 Data types 


Introduction to Verilog 


The Verilog language has many different ‘things’ that can represent 
data, divided into three main categories: nets , variables and events. 
Nets are just wire connections that can be driven with some value, 
but they can not store it; variables are components (connected with 
wires) that can hold and keep a value; events are special variables 
used to hold the triggering of an event. 

Net types represent wires that can have a value only when they are 
driven by some source. If a wire is driven by more than one source 
with different values, then there is a collision and the result on the 
wire is different, depending on the particular net type. 


Table 2.14. Net types. 


Type 

Description 

wire 

A simple wire used to connect components: collisions 
result in unknown value. 

wand 

A wired AND net: collisions result in the AND of the 
values driven to the net. 

wor 

A wired OR net: collisions result in the OR of the values 
driven to the net. 

tri 

Just the same as wire, emphasizing the fact that there 
can be also the floating state. 

triO 

A wire where a floating state is changed into 0. 

tril 

A wire where a floating state is changed into 1. 

triand 

Just the same as wand, emphasizing the fact that there 
can be also the floating state. 












Introduction to Verilog 


65 


Type 

Description 

trior 

Just the same as wor, emphasizing the fact that there can 
be also the floating state. 

trireg 

A wire connected to a virtual capacitor, which can retain 
the last value if it is driven by a floating state. 

supplyO 

A wire directly connected to the ground, resulting al¬ 
ways into the value 0. 

supply1 

A wire directly connected to Vcc (or Vdd), resulting al¬ 
ways into the value 1. 


Variable types represent registers and other container types to which 
a value can be assigned. 


Table 2.15. Variable types. 


Type 

Description 

reg 

A variable that can be used to represent a hardware reg¬ 
ister. 

integer 

A 2’s complement signed integer variable not intended 
to represent a hardware register, which should have at 
least a 32-bit size. 

real 

A floating point (signed) variable not intended to rep¬ 
resent a hardware register, which should have at least a 
32-bit size. 

time 

An unsigned integer variable, with at least a 64-bit size, 
useful for saving the time counted as a number of simu¬ 
lation time units. It is used to hold the value returned by 
the $time system variable. 





66 


Introduction to Verilog 


Please notice that variables of type integer, real and time, are 
useful only for simulated code, but not for what should be synthe¬ 
sized. 

The declarations of nets and reg type variables can be related to a 
single bit or to a numbered range of bits (the types integer, real 
and time have an implied bit size). The following examples show 
the declarations of nets and registers with a single bit size: 


wire wl, w2, w3; 
wire w4; 
supplyO w5, w6; 

supplyl w7; 
reg rl, r2; 
reg r3; 


// wl, w2, w3 and w4 are nets of 
// type 'wire'. 

// w5 and w6 are nets of type 
// 'supplyO'. 

// w7 is a net of type 'supplyl'. 
// rl, r2 and r3 are variables of 
// type 'reg'. 


To declare a ‘word’ of more than one bit, a range of bits is added be¬ 
fore the name of the net or register. This range is enclosed in square 
brackets, as the following syntax should explain: 


[ msb : Isb ] 


For example, the following declaration defines the 16-bit wires wl6a 
and wl6b: 

wire [15:0] wl6a, wl6b; 


For a better compatibility, the range should always start from bit 
zero, up to size- 1, like the example above. 







Introduction to Verilog 


67 


When a net or reg is declared as a single bit, it is known as a ‘scalar’, 
whereas when it is declared with a bit size it is known as a 4 vector’. 

A net or variable, either scalar or vector, might be declared as an 
array, adding a range of elements in square brackets after the name, 
and if the array is of type reg it is also called a memory : 


name [ index_1: index_n ] 

The following example shows a memory made of an array of register 
vectors: 


reg [7:0] mem[0:255]; 

The memory mem is made of 256 8-bit cells, where the first cell is 
reached with the index 0 and the last one with the index 255. 


For a better compatibility, the index range should always start from 
cell zero, up to size- 1, like the example above. 

To access an array element an index is used, in square brackets, just 
like the C language does. The index might be a literal constant or an 
expression that produces an integer value. 


Table 2.19. Event type. 


Type 

Description 

event 

A variable that can be set (triggered) to represent an 
event. 


The event type is a single particular one that is used to store the 
triggering of an event. This kind of variable is read only inside an 









68 


Introduction to Verilog 


event expression and when it is read it loses the trigger previously 
stored. At the moment it is useful to know just how an event variable 
is declared; the following example shows the creation of the event 
variable e : 


event e; 

2.7 Ports 

Almost all the Verilog code must be contained inside a module. 
A module is something like a box connected to the external world 
through ports. So, a port is a connection that can be used to get data 
into the module (input), to put data out of the module (output) or 
to get and put data (inout). 

When declaring a new module the port list should appear in paren¬ 
theses, but then it must be specified the direction of these ports. The 
example below shows the declaration of the module my_module 
with three ports, named a, b and c, used respectively for input, out¬ 
put and both: 


module my_module (a, b, c) ; 
input a; 
output b; 
inout c; 

endmodule 

As it can be seen from the example above, the keywords input, 
output and inout are used to declare a port, with its direction. But 
ports might have a size bigger than a single bit, in that case, the size 
is specified in the same way as for nets and registers. 




Introduction to Verilog 


69 


module my_module (a, b, c); 
input [3:0] a; 
output [2:0] b; 
inout [1:0] c; 

endmodule 

The above example shows that all the ports are vectors of various 
sizes. Please notice that there are no port arrays. 

A port is a connection that, inside the module, might work as a net 
or as reg, but this fact should be specified, otherwise it is assumed 
that the internal connection is seen as a type wire. 


module my_module (a, b, c); 
input [3:0] a; 

output [2:0] b; 

inout [1:0] c; 

reg [2:0] b; 

endmodule 

The above example shows that the port b is driven by the module 
with a memory (it might be a register). The same declaration might 
be done at the same time of the port declaration, in a more elegant 
way: 





70 


Introduction to Verilog 


module my_module (a, b, c) ; 
input [3:0] a; 

output reg [2:0] b; 

inout [1:0] c; 

endmodule 

2.8 Parameters 

Verilog allows to declare symbolic constants, known as parameters. 
The parameter declaration must specify also the value that it rep¬ 
resents, with a literal constant or with an expression where literal 
constants and other parameters can be used. 


module •••; 

parameter DLY = 3; 
parameter XDLY = 3 + DLY; 

endmodule 

The above example shows the declaration of the parameter DLY 
with the value 3 and the parameter XDLY with the value 6. 

The parameters allow to define ‘parameterized’ modules, so that, for 
example, the size of a net or reg can be defined when a module is 
instantiated. These details are described in the following sections, 
about module declaration and module instantiation. 




Introduction to Verilog 

2.9 Module declaration 


71 


Verilog requires that any circuit or procedure be contained inside 
a module. There must be at least a top level module that might 
use other modules. Verilog treats modules as classes of an object- 
oriented language and, except for top level modules, the other mod¬ 
ules are used after their instantiation. Please notice that any module 
that is never instantiated is a top level one. 


module name [ ( port_name [ 
[<declarations ] 

[assign assignment ] ••• 
[primitive-instantiation ] ... 
[module-instantiation^ ... 
[initial block ] ••• 

[always block ] ••• 
endmodule 



The syntax above shows the declaration of a module: it is important 
to notice the position of the semicolon and the absence of it after the 
keyword endmodule. 


A module has usually ports, to communicate with the outside, except 
for the top level module that does not requires them. If ports are 
present, their name should be listed inside parentheses, but the listed 
ports must also be declared specifying their direction and their data 
type. 



72 


Introduction to Verilog 


module my_module (a, b, c); 
input [7:0] a; 
output reg [7:0] b; 
inout [15:0] c; 

endmodule 

The above example declares the module myjnodule with three 
ports: a for input, b for output and c for input-output. The port b 
is declared of type reg, where the other ports are implicitly of type 

wire. 

Usually after the port direction and data type declarations, nets and 
variables might be declared, whereas parameter declarations might 
be better placed even before the port directions, like in the following 
example: 


module my_module (a, b, c); 
parameter N = 8; 
parameter M = N * 2; 
input [N-l:0] a; 
output reg [N-1:0] b; 
inout [M-l:0] c; 
wire wl, w2; 
reg rl, r2, r3; 

endmodule 

The parameter declaration might also appear in-line, before the port 
list inside parentheses, like the following examples, where two dif¬ 
ferent methods are used: 





Introduction to Verilog 


73 



To use a module it must be instantiated, creating a module instance. 
For example, the following code creates the module instance mymol 
from the module myjnodule defined in the previous section: 

my_module mymol (xl, x2, x3) ; 

The module instance mymol of the example above, connects the 
nets or variables xl , x2 and x3 to the original ports a , b and c, 
following the same order. To be more clear the module instance con¬ 
nection might be specified, like the following example: 

my_module mymol (.a(xl), .b(x2), .c(x3)); 






74 


Introduction to Verilog 


A module instance can change some parameter values. If the pa¬ 
rameters are specified in-line, inside the module declaration, like the 
last examples of the previous section, the module instance can be 
obtained as the following example shows: 


my_module #(16, 32) mymol (.a(xl), .b(x2), .c(x3)); 

On the above example, the instance mymol is created assigning to 
the first parameter the value 16 and to the second the value 32. To be 
sure that the parameters are selected correctly the following variation 
might be used: 


my_module #(.N(16), .M(32)) mymol (.a(xl), .b(x2), .c(x3)); 

If the parameters are not specified in-line in the module declaration, 
they can be modified after the module instance is created, with the 
defparam instruction: 

my_module mymo2 (.a(xl), .b(x2), .c(x3)); 

defparam mymo2.DLY = 7; 

The above example shows the instantiation of the module 
myjnodule and then, to the parameter DLY of the newly created 
instance is assigned the value 7. 

2.11 Fully qualified path names 

When the modules are designed properly, the only way to communi¬ 
cate with them is through ports. If, for some reason, it is necessary to 
access directly to an internal net or variable of an instantiated mod¬ 
ule, it is possible to use a fully qualified path name. In fact, this 
approach might be appropriate for debugging purposes. 





Introduction to Verilog 


75 


module main; 

mymo3 myl (...) ; 
endmodule 
module mymo3 (•••) ; 

mymo4 myl (...) ; 
endmodule 
module mymo4 (...) ; 

reg rl; 
endmodule 


The above example shows the declaration of the top level module 
main , where an instance of the module my mo 3 is created with the 
name myl. Then, the module mymo3 contains the creation of an in¬ 
stance of the module mymo4 with the name myl (again). The mod¬ 
ule mymo4 contains the declaration of a reg type variable with the 
name rl. To specify the variable rl of the module mymo4 when 
instantiated in the described way, the following full path might be 
used: 


main.myl.myl.r1 









76 

2.12 Primitives 


Introduction to Verilog 


The Verilog language has already available some modules describing 
the common logical functions and circuits: these modules are called 
primitives. There are gate primitives that simulate a complete logic 
gate, and switch primitives that simulate the internal component of 
an electronic gate. 


and myandl (y, a, b); 

The above example shows the creation of the instance myandl that 
is a logic AND, receiving input from the nets or registers a and b , 
driving output to the y connection. The instance creation might also 
contain a delay, for simulation purposes: 


and #(5) 

myandl 

(y, 

a, b) ; 

and # (5,7) 

myand2 

(z. 

c, d) ; 


As it can be understood, the delay is specified as a parameter value: 
if only one parameter is specified the delay is for rising and falling 
edges, otherwise the first value is the delay after the rising edge and 
the second for the falling one. 

Gate primitives have in common the first gate argument being the 
output, while the others being the inputs, which usually can be one 
or more than one. For example, a logic AND with five inputs might 
be instantiated as shown by the following example: 


and myand3 (y, a, b, c, d, e) ; 

The Verilog primitives are single bit, but the instantiation can be 
requested for an array of the selected primitive. For example: 





Introduction to Verilog 


77 


and myand4[7:0] (y, a, b); 

In that case, the array instance myand4 is created, made of eight and 
primitives in parallel. 


Table 2.43. Gate primitives. 


Primitive 

Ports 

and ( output, input [, input]-) 


or ( output, input [, input]-) 


xor ( output, input input] .) 

Logic AND, OR, XOR, 

nand ( output, input [, input]-) 

NAND, NOR and NXOR. 

nor ( output, input [, input]-) 


nxor ( output, input [, input]-) 


bu f ( output, input) 

Buffer and inverter. 

not ( output, input) 






78 


Introduction to Verilog 


Primitive 

Ports 

bufifO ( output, input, control) 

bufifl ( output, input, control) 

not if 0 ( output, input, control) 

not if 1 ( output, input, control) 

Tri-state buffers and tri¬ 
state inverters. 

pullup ( output) 

pulldown ( output) 

Output equal to logic 1 or 
equal to logic 0. 


Figure 2.44. Tri-state buffer and inverter primitives. 



There are occasions when primitives can be instantiated without as¬ 
signing a name to the instances, because it is not worth knowing that 
name. In that case the instantiations look like a function call, but they 
are not functions and can not be used inside expressions. 


2.13 Expressions 


The Verilog expressions are similar to those of the C language, even 
for the operator precedence and the use of parentheses to force eval¬ 
uation order. When the bit sizes of operands do not match, then the 
bit size of the largest value is used and every operand is extended to 























Introduction to Verilog 79 


that size before the expression is evaluated. 

Table 2.45. Verilog expression operators, grouped by precedence, 
starting from the highest priority, ending with the lowest one. 


Operator 

Description 

{a, b[, c] ...} 

Concatenation - concatenates the bits of 
two or more data objects (nets or regis¬ 
ters) or expressions returning a data object. 
Please notice that a is located at the least 
significant position. 

{n{a}} 

Replication - concatenates n times a . The 
value n must be a constant. 


Operator 

Description 

! a 

Logic NOT - it returns 0 if a is not equal to zero, 1 if a 
is equal to zero. 

~a 

l’s complement of a. 

-a 

2’s complement of a. 

& tt 

Reduction AND - if all the bits of a are set to 1, then 
returns 1, otherwise returns 0. 

I a 

Reduction OR - if all the bits of a are cleared to 0, then 
returns 0, otherwise returns 1. 


Reduction XOR - if there is an odd quantity of bits set 
to one, then returns 1, otherwise returns 0. 

~ 

Reduction NAND - if all the bits of a are cleared to 0, 
then returns 1, otherwise returns 0. 

~ | a 

Reduction NOR - if all the bits of a are set to 1, then 
returns 0, otherwise returns 1. 





80 


Introduction to Verilog 


Operator 

Description 


Reduction NXOR - if there is an odd quantity of bits set 
to one, then returns 0, otherwise returns 1. 


Operator 

Description 

a*b 

Multiplication - returns the product of a and b . 

a/b 

Division - returns the quotient of a and b . 

a%b 

Remainder, modulo - returns the remainder of alb . 


Operator 

Description 

a+b 

Addition - returns the sum of a and b . 

a-b 

Subtraction - returns the difference of a and b . 


Operator 

Description 

a»b 

Logical right shift - returns the value of a shifted right 
b times. 

a«b 

Logical left shift - returns the value of a shifted left b 
times. 

a»>b 

Arithmetic right shift - returns the value of a shifted 
right b times, arithmetically. 

a«<b 

Arithmetic left shift - returns the value of a shifted left 
b times, arithmetically. 







Introduction to Verilog 


81 


Operator 

Description 

a>b 

Greater then - returns 1 if a is greater than b, otherwise 
returns 0. 

a<b 

Less then - returns 1 if a is less than b, otherwise returns 
0. 

a>=b 

Greater then or equal - returns 1 if a is greater than or 
equal to b , otherwise returns 0. 

a<=b 

Less then or equal - returns 1 if a is less than or equal 
to b , otherwise returns 0. 


Operator 

Description 

a==b 

Equality - returns 1 if a and b are equal and 0 if they 
are not. Returns unknown (x) if any bit inside a or b are 
unknown or floating (z). 

a ! =b 

Inequality - returns 0 if a and b are equal and 1 if they 
are not. Returns unknown (x) if any bit inside a or b are 
unknown or floating (z). 

a===b 

Case equality - returns 1 if a and b are exactly the same, 
included unknown and floating bits, otherwise it returns 
0. 

a ! ==b 

Case inequality - returns 0 if a and b are exactly the 
same, included unknown and floating bits, otherwise it 
returns 1. 


Operator 

Description 

a&b 

Bitwise AND - returns a AND b , bit by bit. 

a~&b 

Bitwise NAND - returns (a AND b), bit by bit. 






82 


Introduction to Verilog 


Operator 

Description 

a^b 

Bitwise XOR - returns a XOR b, bit by bit. 

a~*b 

Bitwise NXOR - returns (a XOR b ), bit by bit. 


Operator 

Description 

a | b 

Bitwise OR - returns a OR b, bit by bit. 

I b 

Bitwise NOR - returns (a OR b), bit by bit. 


Operator 

Description 

a & Scb 

Logical AND - returns 1 if a and b have both a value 
different from zero, otherwise it returns zero. If there 
are unknown or floating bits, it might be impossible to 
determine the result: in that case the result is unknown 
as well. 


Operator 

Description 

a | | b 

Logical OR - returns 1 if either a or b contains a value 
different from zero, otherwise it returns zero. If there 
are unknown or floating bits, it might be impossible to 
determine the result: in that case the result is unknown 
as well. 


Operator 

Description 

alb :c 

Conditional operator - returns b if a is different from 
zero, returns c if a is equal to 0; if a is unknown or 
floating, the result is the same as b A c (bitwise b XOR 
c). 








Introduction to Verilog 


83 


2.14 Vector and array addressing 

A multi-bit net or variable (vector) can be addressed globally —as 
usual— or partially. To address a single bit the following syntax is 
used: 


name [bit] 


For example, the variable rl is declared having an 8-bit size, like 
this: 


reg [7:0] rl; 

To access the third bit (r/ 2 ) the notation rl [2] might be used. The 
index that represents the selected bit might be a constant or an ex¬ 
pression with variables or constants (care must be taken to avoid to 
select a bit position that does not exists). Also a range might be se¬ 
lected with the following syntax: 


name [ msb : Isb ] 


For example, to select the bit-range rl 5 2 the notation rl[5:2] 
should be used. The values for msb and Isb must be constant, or 
constant expressions. It is possible to use a variable index to select a 
bit range, with the following syntax: 


name [ lsb+: size ] 


For example, as above, to select the bit-range rl 52 the notation 
rl [2+: 4] could be used, but this time, the value for Isb can be 







84 


Introduction to Verilog 

an expression with variables, whereas the size must be constant (or 
a constant expression). 

To access an array element, the notation used is just the same as the 
bit selection for vectored nets or variables: 


name [ element ] 


For example, there might be a static memory of 256 bytes, defined 
like this: 


reg [7:0] ml[255:0]; 

To access the byte at address 123 the notation ml [123] might be 
used. Ranges of array elements are not available, but the bits inside 
a selected element are reachable, the same way as explained above. 
For example, to select the bit ml[123]j„ the notation ml [123] [3] 
might be used. 

2.15 Strings 

Strings are numbers for Verilog, represented as bit vectors, where 
each character is placed in a different bit octet. The following exam¬ 
ple declares a reg variable big enough to hold the string "Hello!": 




Introduction to Verilog 


85 



When the variable str is assigned, it contains exactly the value 
48656C6C6F21 i 6 . If the receiving variable is bigger than the re¬ 
quired space, it is padded just like a numeric value, on the left! 



In the above example, the variable str is assigned and then it contains 
the value 000048656C6C6F21 i 6 . The same way, assigning an empty 
string to a variable is just the same as assigning 0. 


2.16 Functions 

Verilog includes the ability to define functions in a similar way to 
the C language. There are two alternative syntaxes: 




86 


Introduction to Verilog 


function [automatic ] [ range_or_type ] function_name ; 

input [size] input_port ; 

begin 

statement ; 

function_name = value ; 

end 


function [automatic ] [ range _or_type ] ^ 

^ function_name (input [size] input_port[, •••]); 

begin 

statement ; 

function_name = value ; 

end 

Verilog functions should be used in expressions, as they return a 
value. The value returned by a function is of the type specified by 
the range_or_type, which is a range in the form of [ msb : Isb ] or a 
variable type with implicit range (like integer). The Verilog func¬ 
tions do not have a ‘return’ statement, instead they must assign a 
value to a variable with the same name as the function, at the end 
of it (like the syntaxes above show). The Verilog functions can have 




87 


Introduction to Verilog 


only input ports as arguments. 

Normal Verilog functions are implicitly ‘static’, which means that 
the local variables are unique and shared with all concurrent calls: 
if two threads call the same function, it is difficult to predict the 
result. To make functions work like in C, where local variables are 
implicitly ‘automatic’ (because they are created inside a stack), the 
keyword automatic must be added to the function declaration. The 
automatic keyword means that each function call creates a private 
instance of the whole function. 


Figure 2.50. Full adder. 


Ci 

V 


A > 



^ S 


A © B © Ci 


B > 


^ Co = A B +((A®B) • Ci) 


The above figure shows the common circuit of a full adder, where for 
each output the logic expression is reported. The following functions 
reproduce the same calculations: 


function S (input A , input B, input Ci); 
begin 

S = A A B A Ci; 

end 





88 


Introduction to Verilog 


function Co (input A, input B, input Ci); 
begin 

Co = A&B + ( (A A B) & Ci) ; 

end 

Functions are used as a way to simplify expressions, through a se¬ 
quential process that can not contain explicit delays. 

2.17 Netlist modules: combinational circuits 

A netlist module is made of components connected only with nets, 
without variables. Assignments inside this kind of modules are 
called continuous , because they just update continuously and can 
be defined when declaring the net or separately with the assign 
statement. The following examples show two alternative ways for 
defining a continuous assignment to the net wl : 



The following figure shows a full adder netlist module that is to be 
written in Verilog code: all the connections and gates are named. 





Introduction to Verilog 


89 


Figure 2.55. Full adder. 


Ci 

V 



To build the above example in Verilog, as a netlist module, can be 
used primitives or assignments, in various ways. The following code 
example shows the use of primitive instantiation without assigning a 
particular name to the gates that they represent: 




































90 


Introduction to Verilog 


module ADD 

(S, Co, A, B, Ci); 

output S 

o 

o 

> • 

input A, 

B, Ci; 

wire wl. 

• < 

■S 

< 

00 

£ 

xor (wl. 

A, B) ; 

xor (S, 

wl, Ci) ; 

and (w3. 

wl, Ci) ; 

and (w4. 

A, B) ; 

or (Co, 

w3, w4); 

endmodule 



The primitive instances can be declared with a name: 


module ADD (S, Co, A, B, Ci); 
output S, Co; 
input A, B, Ci; 
wire wl, w3, w4; 
xor gi (wl, A, B) ; 
xor g2 (S, wl, Ci); 
and g3 (w3, wl, Ci); 
and g4 (w4, A, B); 
or g5 (Co, w3, w4); 
endmodule 


Instead of the primitives, a continuous assignment can be used: 





Introduction to Verilog 


91 


module ADD (S, Co, A, B, Ci); 


output 

s. 

o 

o 

> • 


input A, 

B, Ci; 


wire wl 

r 

■s 

< 

00 

■S 

• 

f 

assign 

wl 

= A A 

B; 

assign 

S 

= wl A 

Ci; 

assign 

w3 

= wl 

& Ci; 

assign 

w4 

= A & 

B; 

assign 

Co 

= w3 

1 w4; 


endmodule 

The continuous assignment can be defined with the wire and port 
declarations: 

module ADD (S, Co, A, B, Ci); 
output S = wl A Ci; 
output Co = w3 | w4; 
input A, B, Ci; 
wire wl = A A B; 
wire w3 = wl & Ci; 
wire w4 = A & B; 
endmodule 

Even functions might be used: 

module ADD (S, Co, A, B, Ci); 
output S, Co; 
input A, B, Ci; 

function sum (input A, input B, input Ci); 
begin 

S = A A B A Ci; 
end 






92 


Introduction to Verilog 


function carry (input A, input B, input Ci); 
begin 

Co = A & B + ((A A B) & Ci) ; 
end 

assign S = sum (A, B, Ci); 
assign Co = carry (A, B, Ci) ; 

endmodule 


module ADD (S, Co, A, B, Ci); 
output S = sum (A, B, Ci) ; 
output Co = carry (A, B, Ci) ; 

input A, B, Ci; 

function sum (input A, input B, input Ci); 
begin 

S = A A B A Ci; 
end 

function carry (input A, input B, input Ci); 
begin 

Co = A & B + ((A A B) & Ci); 
end 

endmodule 


The same examples can be made adding delays: 







Introduction to Verilog 


module ADD (S, Co, A, B, Ci) 
output S, Co; 
input A, B, Ci; 
wire wl, w3, w4; 
xor #( 8 ) (wl, A, B) ; 
xor #( 8 ) (S, wl, Ci) ; 

and #( 6 ) (w3, wl, Ci) ; 

and #( 6 ) (w4, A, B) ; 

or #( 6 ) (Co, w3, w4); 
endmodule 


module ADD (S, Co, A, B, Ci) 
output S, Co; 
input A, B, Ci; 
wire wl, w3, w4; 
xor #( 8 ) gl (wl. A, B); 
xor #( 8 ) g2 (S, wl, Ci) ; 
and #( 6 ) g3 (w3, wl, Ci); 
and #( 6 ) g4 (w4. A, B) ; 
or #( 6 ) g5 (Co, w3, w4); 
endmodule 





Introduction to Verilog 


module ADD (S, Co, A, B, Ci); 
output S, Co; 
input A, B, Ci; 
wire wl, w3, w4; 
assign #( 8 ) wl = A A B; 
assign #( 8 ) S = wl A Ci; 
assign #( 6 ) w3 = wl & Ci; 
assign #( 6 ) w4 = A & B; 
assign #( 6 ) Co = w3 | w4; 
endmodule 

module ADD (S, Co, A, B, Ci); 
output S = #8 wl A Ci; 
output Co = #6 w3 | w4; 
input A, B, Ci; 
wire wl = #6 A A B; 
wire w3 = #6 wl & Ci; 
wire w4 = #6 A & B; 
endmodule 

module ADD (S, Co, A, B, Ci); 
output S, Co; 
input A, B, Ci; 

function sum (input A, input B, input Ci); 
begin 

S = A A B A Ci; 
end 

function carry (input A, input B, input Ci); 
begin 

Co = A & B + ((A A B) & Ci); 






Introduction to Verilog 


95 


end 

assign #16 S = sum (A, B, Ci) ; 
assign #14 Co = carry (A, B, Ci) ; 
endmodule 


module ADD (S, Co, A, B, Ci); 

output S = #16 sum (A, B, Ci); 
output Co = #14 carry (A, B, Ci); 
input A, B, Ci; 

function sum (input A, input B, input Ci); 
begin 

S = A A B A Ci; 
end 

function carry (input A, input B, input Ci); 
begin 

Co = A & B + ((A A B) & Ci); 

end 

endmodule 


2.18 Behavioural modules 

The module description can contain two types of code block: 
initial or always. These blocks of code describe a sequence of 
operations, like it happens in the C language, but each block declared 
inside the module corresponds to a different thread. The initial 
blocks are executed only once, whereas the always blocks are exe¬ 
cuted repeatedly in a never ending loop. Inside a module there might 
be any number of initial and always blocks. The sequential code 
that is contained inside these blocks is delimited by the keywords 




96 


Introduction to Verilog 
begin and end, because the curly brackets are used as operators. 


module ADD (S, Co, A, 

B, Ci); 

output reg S, Co; 


input A, B, Ci; 


always 


begin 


S=A+B+Ci; 


Co = ~(A A B A 

Ci) ; 

end 


endmodule 



The above code transforms the netlist examples of the previous sec¬ 
tion in the form of a behavioural module. In this case, it is first cal¬ 
culated the sum of the inputs and then the carry-out, but as there 
are no delays, it all happens simultaneously. Please notice that the 
output ports are now changed into a reg type, because inside the 
behavioural blocks the assignments need to modify a reg type des¬ 
tination. 


Verilog allows to describe the hardware at different abstraction 
levels, but not all the behavioural code can always be synthesized 
into a real hardware. 


2.19 Procedural assignments 

The assignments inside the procedural blocks (behavioural) are 
known as procedural assignments , as they differ from the contin¬ 
uous assignments used outside blocks. The procedural assignments 
require to have a reg type variable on the left side of the assignment, 




97 


Introduction to Verilog 

whereas the continuous assignments require a net type destination. 

There are two types of procedural assignments: blocking and non- 
blocking. Blocking assignments appear and work like the C lan¬ 
guage assignments. The adjective ‘blocking’ means that the assign¬ 
ment must be done before the next sentences are executed. 

Inside the following example —which already appeared in a previ¬ 
ous section— there are two blocking assignments: they just mean 
that first the sum is assigned to the output variable S and then that 
the carry-out is assigned to the output variable Co. 



Non-blocking assignments are similar to the blocking ones, but they 
are executed in a separate thread. The following example does the 
same work as the previous one, but the assignments just happens 
simultaneously: 




98 


Introduction to Verilog 


module ADD (S, Co, A, B, Ci); 
output reg S, Co; 
input A, B, Ci; 
always 
begin 

S <= A + B + Ci; 

Co <= -(A A B A Ci) ; 

end 

endmodule 

Assignments can be delayed, using the following syntax, for block¬ 
ing and non-blocking assignments: 


cist = ^ delay ^ expression 


dst <= delay ^ expression 

The following example is a modified version of the blocking assign¬ 
ment one, shown above, adding a 14 time units delay before the sum 
is calculated: 





Introduction to Verilog 


99 



In the above example, the value for Co is calculated only after the 
assignment for S, so the output variables are updated at the same 
time, with the same delay. The following example uses non-blocking 
assignments and it has a different behaviour, because the two assign¬ 
ments are independent each other: 



In the above example, the second assignment does not wait for the 
first one and the delay is less than the first one. This means that the 
Co output variable is updated before the S variable. 





100 


Introduction to Verilog 


2.20 Blocking delays 

The execution of each statement inside a procedural block can be 
delayed, placing a delay number before the statement itself: 


$ delay [ procedural-Statement^ ; 

Please notice that the delayed statement is optional, so that the delay 
can be alone, like an autonomous statement. The following exam¬ 
ple shows a variation of the delayed blocking assignments, with the 
delay specified before the assignment statement: 

module ADD (S, Co, A, B, Ci); 
output reg S, Co; 
input A, B, Ci; 
always 
begin 

#14 S = A + B + Ci; 

Co = ~(A A B A Ci); 
end 

endmodule 

Please notice that 

#14 S = A + B + Ci; 

is just the same as 


# 14 ; 

S = A + B + Ci; 


When non-blocking assignments are used, care must be taken using 
the blocking assignments; for example, 






Introduction to Verilog 


101 


S <= #14 A + B + Ci; 

Co <= #12 ~(A A B A Ci); 

is much different from the following: 


#14 S <= A + B + Ci; 

#12 Co <= ~(A A B A Ci); 

The last example above just means: wait 14 time units, then assign 
the sum to S (without waiting), then wait another 12 time units, then 
assign the carry-out to Co (without waiting). In fact, the carry-out is 
assigned after 26 time units. 

2.21 Wait for a level event 

Inside a procedural block it is possible to wait for a value being 
available in a net or variable data type: this is called level event. The 
wait statement is used to test a level event: 



The following example should implement a D latch: 






102 


Introduction to Verilog 


module latch_d (Q, _Q, D, Clk) ; 
input D, Clk; 
output reg Q, _Q; 
always 
begin 

wait (Clk == 1) 
begin 

#10 Q = D; 

_Q = ~D; 

end 

end 

endmodule 

The above example just waits for the Clk input to be 1, then it up¬ 
dates the outputs (with a 10 time units delay); if the Clk is already at 
the 1 level, the outputs keep updating. The statement (or the group 
of statements) that follows the wait condition, might be omitted, if 
there is only the need to wait for the level event: 


module latch_d (Q, _Q, D, Clk) ; 
input D, Clk; 
output reg Q, _Q; 
always 
begin 

wait (Clk == 1); 

#10 Q = D; 

_Q = ~D; 
end 

endmodule 





Introduction to Verilog 


103 


2.22 Wait for an event expressions 

The following syntax is used to wait until an event condition is true 
(triggered). Please notice that the event condition is different from 
the level condition used by the wait statement. 



The event expression is different from common expressions, because 
it is meant to be true when a specified event occurs. 


Table 2.80. Basic event expressions. 


Expression 

Description 

a 

When the a net or variable changes value, 
an event occurs. 

posedge a 

When the a net or variable changes value 
becoming 1 (positive edge). 

negedge a 

When the a net or variable changes value 
becoming 0 (negative edge). 

el or e2 

When any of the two events (el or e2) be¬ 
comes true. 











104 


Introduction to Verilog 


The following example should implement a D flip-flop triggered by 
a positive edge clock signal. Please notice that the always statement 
is followed by the @ statement, which owns the begin-end block. 


module ff_d (Q, _Q, D, Clk); 
input D, Clk; 
output reg Q, _Q; 
always @ (posedge Clk) 
begin 

Q = #10 D; 

_Q = ~Q; 

end 

endmodule 

The same thing could also be done using the @ statement just to wait 
time, blocking the procedure flow until the event occurs: 

module ff_d (Q, _Q, D, Clk); 
input D, Clk; 
output reg Q, _Q; 
always 
begin 

@ (posedge Clk); 

Q = #10 D; 

_Q = ~Q; 
end 

endmodule 





Introduction to Verilog 

2.23 Event variables 


105 


Event variables are only able to store the triggering of an event, with 
the -> operator: 


begin 
-> e; 

end 

An event can be risen inside an event variable only in a procedural 
context, as the above example might suggest. An event variable can 
be used as an event expression or subexpression: 


@ (e) •••; _ 

2.24 System tasks and functions 

Verilog provides some special functions for the simulation purpose, 
to be used inside procedural blocks, characterized by the $ (dollar) 
prefix, useful mainly for debugging. The most important of these 
functions is $display (), which allows to show some text (to the 
simulation output console) in a similar way to print f () for the C 
language. 

module •••; 

reg [7:0] x, y , z; 

initial 

begin 





106 


Introduction to Verilog 


• < 

\—1 

& 

< 

00 

ii 

// A 

x = 8'hab; 


y = 8'hcd; 


z = 8'hef; 


$display ("Hello: 

w=%c, x=%d, y=0x%h, z=%b". 

w, x, y. 

z) ; 

end 


endmodule 



The above example should display the following text on the simula¬ 
tion console: 

Hello: w=A, x=171, y=0xcd, z=11101111 


Table 2.87. Common system functions. 


System function 

Description 

$display (string jc] •••) 

It displays on the simulation con¬ 
sole the string, expanding the 
metavariables %... with the value 
provided by the nets and variables 
that form the following arguments. 
It works like the printf () func¬ 
tion for the C language, except that 
it is displayed with a new-line at 
the end. 








Introduction to Verilog 


107 


System function 

Description 

$monitor ( string , x [, y] •••) 

Continuous monitoring: whenever 
one of the arguments following the 
string changes value, the string is 
displayed on the simulation con¬ 
sole, expanding the metavariables 
%... with the value provided by 
the nets and variables that form 
the following arguments. It works 
like the print f () function for the 
C language, except that it is dis¬ 
played with a new-line at the end. 
Generally, this function is used 
only on initial blocks, because 
once requested, it remains active. 

$t ime 

It returns a value corresponding 
to the current time, which is ex¬ 
pressed in the unit specified with 
the 'timescale directive. The 
time value can be assigned to a 
time variable type and can be 
shown inside $display () or sim¬ 
ilar functions with the metavari¬ 
able %t. 

$finish 

It stops the simulation. 




108 

2.25 Control structures 


Introduction to Verilog 


Inside a procedural block, many of the common C language con¬ 
trol structures can be used. However it must be remembered that the 
group of statements is made in Verilog language with the keywords 
begin-end, because the curly brackets are used as operators. 

Syntax 2.88. Conditional statement: if. 

i f ( condition) 
statement ; 

[else 

statement ; ] 


Syntax 2.89. Selection statement: case. 


case 

casez 

c a s e x ( expression) 

case jexpression : statement ; 

[default: 

statement ; ] 

endcase 



The selection statement requires some explanations. The first thing 
that should be noticed is that the value in parentheses —that should 
be compared with the case list below— is an expression, which is 
evaluated at run time. The same is for the case conditions appearing 
below, which are expressions evaluated at run time. Then, after each 
case condition there is only one statement and there is no ‘break 4 
keyword (the single statement might be expanded with the keywords 








109 


Introduction to Verilog 

begin-end). 

There are three types of case statements: case matches the expres¬ 
sion in parentheses exactly, even the floating and unknown values 
(z and x) should be the same; casez considers that floating values 
are don’t-care values (a don’t-care bit value always match); casex 
considers that floating and unknown are don’t-care values. 

Syntax 2.90. Loop statement: while. 


while ( condition) 
statement ; 


Syntax 2.91. Loop statement: for. 


for ( initialization ; condition ; statement) 
statement ; 

The following example shows a typical use of the for loop; please 
notice that the i variable is declared as integer type: 

module •••; 

reg [7:0] m[1023:0]; 
integer i; 

always 

begin 

for (i = 0; i < 1024; i = i + 1) 
begin 





110 


Introduction to Verilog 


end 

end 

endmodule 


Syntax 2.93. Loop statement: repeat. 


repeat {count) 
statement ; 

The repeat loop executes the statement (or the group of statements) 
a fixed number of time, as defined by the count expression. If the 
count expression has an invalid value, it is treated as zero. 

Syntax 2.94. Loop statement: forever. 


forever 

statement ; 

The forever loop executes the statement (or the group of state¬ 
ments) indefinitely and the statements after the structure would never 
be executed. 

2.26 Thread control 

Every procedure inside an initial or always block has a different 
thread, but inside a procedure a group of threads that should be syn¬ 
chronized can be declared with a special block called fork-join. 





Introduction to Verilog 


111 


fork 

statement ; 
statement ; 

join 

The statements inside the fork-join block are started simultane¬ 
ously, but before leaving the block it is ensured that all these state¬ 
ments have completed their work. 

If instead of a single statement a begin-end group is placed, the 
contained statements are executed sequentially in a single thread. 

Identifiers might also contain other escaped characters, but this pos¬ 
sibility should be avoided and it is not taken into account inside the 
chapter. 

Please notice that the syntax is simplified and it does not consider 
the signedness, because the chapter takes into account only the un¬ 
signed representation. 

The value 232i 0 is equal to 11101000 2 , but allowing only seven bits, 
the value is truncated to 1101000 2 that is equal to 104i 0 . 



Introduction to Verilog 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


113 

Combinational circuits 


Chapter 


« 


3.1 Decoder . 119 

3.2 Demultiplexer . 122 

3.3 Multiplexer . 127 

3.4 Multiplexer and demultiplexer with parallel I/O. 131 

3.5 Binary encoder . 136 

3.6 Priority encoder . 140 

3.7 Logic units . 144 

3.8 Shift and rotation . 146 

3.9 Addition . 154 

3.10 Subtraction . 162 

3.11 Addition and subtraction together. 169 

3.12 Carry lookahead . 173 

3.13 Increment and decrement . 183 

3.14 2’s complement . 189 

3.15 Multiplication. 191 

3.16 Division . 202 

3.17 Magnitude comparator . 206 


2’s complement 189 adder 154 arithmetic shift 146 binary encoder 
136 carry lookahead 173 combinational circuit 113 combinational 
network 113 data distributor 122 data selector 127 decoder 119 
decrement 183 demultiplexer 122 demux 122 encoder 136 fast 



















114 Combinational circuits 

adder 173 full-adder 154 half-adder 154 half-subtractor 162 
increment 183 logic shift 146 logic unit 144 lookahead generator 
173 multiplexer 127 priority encoder 140 ripple-carry 154 rotation 
146 shift 146 subtraction 162 two’s complement 189 


A combinational circuit , otherwise known as combinational net¬ 
work , is a system of logic gates conveniently connected together, 
organized with a set of input ports and a set of output ports, where 
the output logic values are directly and univocally defined by the in¬ 
put logic ones. The overall combinational circuit can be represented 
as a box with input and output ports, together with a truth table that 
describes the output values based on the input combinations. 

r a 


input 


combinational 

circuit 


output 


V 


J 


The figure above shows a combinational circuit example with five 
input ports and three output ports, but the proportion between input 
and output ports depends on the function that should be performed 
by the circuit, or rather from the purpose that the circuit should sat¬ 
isfy. 














Combinational circuits 


115 


Please notice that a combinational circuit is not influenced by the 
time variable and even by the power-on random variable; there¬ 
fore, inside these circuits, the propagation delay does not affect 
the result, because, after a certain delay from the input change, the 
output is updated as specified by the truth table. 

The simpler combinational circuits are those that have only one out¬ 
put port, which are better known as logic gates. 

Figure 3.2. Combinational circuits with a single output port. 


n input 
ports 


To understand better the matter, it can be noticed that a circuit com¬ 
posed only by a single input port and a single output port can be 
made in four different ways, as evidenced by the following figures. 

Figure 3.3. Combinational circuit with one input and one output. 


one output 
port 


one input 
port 


A 


f 



one output 
port 












116 


Combinational circuits 


Figure 3.4. Truth table about four functions of a single variable. 


r 'n 

input 

A 

V J 

types distinguished on the 
output values 

fo /i fi h 

V J 

( } 

0 

l 

V _ J 

? \ 

0 10 1 

0 0 11 

_ J 



1 



NOT A 



As it can be seen on the annotations inside the above figure, the cir¬ 
cuit corresponding to the fi function is the inverter (NOT), whereas 
the one corresponding to the f 2 function is the buffer (not-inverter). 


A combinational circuit with two input ports and a single output 
can have 16 alternative functions, as it can be seen in the follow¬ 
ing figures, where the functions corresponding to the common logic 
ports are evidenced. 




Combinational circuits 


Figure 3.5. Combinational circuit with two inputs and one output. 

f \ 

A 

/ 

B 

v_ ) 


2 input 
ports 


one output 
port 




IS 


Combinational circuits 


Figure 3.6. Truth table about sixteen functions of two variables. 


"\ 

input 

/ 




types distinguished 

r/ze output values 




N 

A 

B 

J 

fo 

V 

fl 

fl 

/ 3 

fi 

ft 

/« 

/ 7 

ft 

/» 

Xo 

fn 

fn 


X. 

ft 

J 

0 

0 

r 

0 

1 

0 

1 

0 

1 

0 

1 

0 

1 

0 

1 

0 

1 

0 

1 

0 

1 

0 

0 

1 

1 

0 

0 

1 

1 

0 

0 

1 

1 

0 

0 

1 

1 

1 

0 

0 

0 

0 

0 

1 

1 

1 

1 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

1 




Combinational circuits 


119 


3.1 Decoder 


The decoder is a combinational circuit that, for every input combina¬ 
tion, asserts only one output port. Precisely, for every input combi¬ 
nation there is only one output port to assert. Therefore, for n input 
ports there are 2" output ports. Usually, this kind of combinational 
circuit has also an additional input control port that should be as¬ 
serted to enable the output. 


Figure 3.7. Block diagram of a decoder with four output ports 
(2-to-4). The two selection input ports are labeled as A 0 and Ai 
(address); the input control port is labeled as E (enable); the out¬ 
put ports are labeled from Y 0 to Y 3 . The drawing on the right is 
more compact and the selection input ports are grouped together. 


address 


enable 




Y0..Y3 




















120 


Combinational circuits 


Table 3.8. Truth table for a decoder with four output ports, from 
Y 0 to Y 3 ; two selection input ports, A 0 and A 7 ; one enable input 
port E. 


E 

A; 

Ao 

y 3 

y 2 

Yj 

Y 0 

0 

X 

X 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

1 

1 

0 

1 

0 

0 

1 

0 

1 

1 

0 

0 

1 

0 

0 

1 

1 

1 

1 

0 

0 

0 


Figure 3.9. Two examples of implementation of a decoder with 
four output ports: the two selection ports are labeled A 0 and A/, 
the enable port is labeled E and the output ports are labeled from 
Y 0 to Y 3 . 


AO >" 

A1 > 


E >' 


-Q 


-or 


> 


> 


> 


> 


Y0 


Y1 


Y2 


A1 > 
AO >■ 


Y3 


A1 




AO 


A 

E 


J-> Y0 


J-> Y1 


3-> Y2 

3-> Y3 


Listing 3.10. Example with Verilog. 

module decoder_2_to_4 (Y, A, E); 
input [1:0] A; 
input E; 
output [3:0] Y; 






Combinational circuits 


121 


// 

function [3 

:0] f2to4 (input [1:0] A, input E); 

if (E == 

1) 

begin 


case 

(A) 

0: 

f2to4 = 4'b0001; 

1: 

f2to4 = 4'b 0 010; 

2 : 

f2to4 = 4'b0100; 

3: 

f2to4 = 4'bl000; 

endcase 

end 


else 


begin 


f 2to4 

= 4'b0000; 

end 


endfunction 

// 

assign #8 Y 

= f2to4 (A, E); 

endmodule 



Listing 3.11. Verilog gate level alternative code following the 
picture 3.9 on the left. 


module decoder_2_ 

to_ 

_4 (Y, 

A, 

E) ; 

input 

[1:0] A; 





input ; 

E; 





output 

[3:0] Y; 





assign 

Y[0] = E 

& 

~A [ 1 ] 

& 

• < 

O 

assign 

k; 

i-1 

i— 1 

II 

& 

~A [ 1 ] 

& 

A [ 0 ] ; 

assign 

Y [2] = E 

& 

A [ 1 ] 

& 

~A[0]; 





122 


Combinational circuits 


assign Y[3] = E & A[l] & A[0]; 

endmodule 


Listing 3.12. Verilog gate level alternative code following the 
picture 3.9 on the right. 


module decoder_2_to_4 (Y, 
input [1:0] A; 
input E; 
output [3:0] Y; 
wire [1:0] _A; 
assign _A = ~A; 
assign Y[0] = E & _A[1] 
assign Y[l] = E & _A[1] 
assign Y[2] = E & A[l] 
assign Y[3] = E & A[l] 
endmodule 


A, E); 


& _A[0]; 
& A [ 0 ] ; 
& _A [ 0 ]; 
& A [ 0 ] ; 


3.2 Demultiplexer 

The demultiplexer (demux), known also as data distributor , is a 
combinational circuit that works like a decoder with an additional 
input port switched to the selected output. 




Combinational circuits 


123 


Figure 3.13. Block diagram of a demultiplexer with four output 
ports. The two selection input ports are labeled A 0 and A 7 , the 
data input corresponds to the variable D , the enable input is E , 
the output ports are labeled from Y 0 to Y 3 . The drawing on the 
right is more compact and the input selection ports are grouped 
together. 


address 


data -► 


enable 

The difference between the decoder and the demultiplexer should be 
clear from the figure above: the Y n output port selected has the same 
value read at the D input (unless the enable port is negated). 

Table 3.14. Truth table for a demultiplexer with four output ports, 
from Y 0 to Y 3 ; two selection input ports, A 0 and A 7 ; a data input 
D ; an enable input E. 


E 

At 

Ao 

D 

y 3 

y 2 

Yj 

Y 0 

0 

X 

X 

d 

0 

0 

0 

0 

1 

0 

0 

d 

0 

0 

0 

d 

1 

0 

1 

d 

0 

0 

d 

0 

1 

1 

0 

d 

0 

d 

0 

0 

1 

1 

1 

d 

d 

0 

0 

0 


AO 

YO 

A1 demux 

Y1 


Y2 

D 


E 

Y3 


AO, 



Y0..Y3 
























124 


Combinational circuits 


Figure 3.15. Two examples of implementation of a demultiplexer 
with four output ports: the two selection ports are labeled A 0 and 
Ai, the data to be switched to the selected output is read from 
the input D, the enable port is labeled E and the output ports are 
labeled from Y 0 to Y 3 . 


AO > 


AI > 

D > 


E > 





> 

) 


> YO 

^ Y1 

> Y2 

^ Y3 



A A 

D E 


It should be noticed that D and E work just like alternative enabling 
inputs, so the truth table might be simplified as it appears below. 


Table 3.16. Alternative way to represent the truth table of the 
demultiplexer with four outputs. Please notice that here the data 
and enable inputs are both at the beginning. 


E 

D 

A; 

Ao 

y 3 

y 2 

Yj 

Y 0 

0 

X 

X 

X 

0 

0 

0 

0 

X 

0 

X 

X 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

1 

1 

1 

0 

1 

0 

0 

1 

0 

1 

1 

1 

0 

0 

1 

0 

0 

1 

1 

1 

1 

1 

0 

0 

0 






Combinational circuits 


125 


Listing 3.17. Example with Verilog. 


module demultiplexer_2_to_4 (Y, A, D, 

E) ; 

input [1:0] 
input D, E; 

A; 


output [3:0] Y; 


// 

function [3 

:0] f2to4 (input [1:0] A, 

input D, 


input E); 


if (E == 

1 && D == 1) 


begin 



case 

(A) 


0: 

f2to4 = 4'b0001; 


1: 

f2to4 = 4'b0010; 


2 : 

f2to4 = 4'b0100; 


3: 

f2to4 = 4'bl000; 


endcase 


end 



else 



begin 



f 2to4 

= 4'b0000; 


end 



endfunction 

// 

assign #8 Y 

= f2to4 (A, D, E); 


endmodule 






126 


Combinational circuits 


Listing 3.18. Verilog gate level alternative code following the 
picture 3.15 on the left. 

module demultiplexer_2_to_4 (Y, A, D, E); 
input [1:0] A; 
input E, D; 


output 

[ 

3:0] 

Y; 









assign 

Y 

[0] 

= E 

& 

D 

& 

~A 

[1] 

& 

~A 

[0] ; 

assign 

Y 

[1] 

= E 

& 

D 

& 

~A 

[1] 

& 

A 

[0] ; 

assign 

Y 

[2] 

= E 

& 

D 

& 

A 

[1] 

& 

~A 

[0] ; 

assign 

Y 

[3] 

= E 

& 

D 

& 

A 

[1] 

& 

A 

[0] ; 


endmodule 


Listing 3.19. Verilog gate level alternative code following the 
picture 3.9 on the right. 


module demultiplexer_2_to_4 (Y, A, D, E); 
input [1:0] A; 
input E, D; 


output [3:0] Y; 
wire [1:0] _A; 
assign _A = ~A; 
assign Y[0] = E 
assign Y[1] = E 

assign Y[2] = E 
assign Y[3] = E 


& D & A [ 1 ] 

& D & A [ 1 ] 

& D & A [ 1 ] 

& D & A [ 1 ] 


endmodule 


& _A[0]; 
& A [ 0 ] ; 
& _A [ 0 ] ; 
& A [ 0 ] ; 


A demultiplexer can be obtained from a decoder (provided that it 
has the enable input port), likewise a demultiplexer can be reduced 
to work as a decoder. 






Combinational circuits 


127 


Figure 3.20. On the left a decoder is adapted to work as a de¬ 
multiplexer; on the right a demultiplexer is adapted to work as a 
decoder. 


D 


AO 

Y0 

A1 

decoder 

Y1 


Y2 

E 

Y3 



E 

Common demultiplexer integrated circuits are 74154, 74138, 74139 
and 74238 (see section uO.l). 


3.3 Multiplexer 

The multiplexer (mux), or data selector , is a combinational circuit 
that selects the value of a single input port and reproduces that value 
to the output port. The input port chosen depends on the value of 
a group of selection ports (or address ports). For n selection ports 
there can be 2 n input ports. 



























128 


Combinational circuits 


Figure 3.21. Block diagram of a multiplexer with four input 
ports. The two selection inputs are labeled A 0 and A/, the data 
input ports are labeled from D 0 to D 3 , the enable input is E, the 
output is Y. On the right it is shown a compact representation 
where the selection variables are joined together in a multiple 
line. 


address or 
selection 


input ports 
to choose from 


enable 


-► 

AO 

Y' 

-► 

A1 


-► 

DO 

mux 


D1 


-► 

D2 


-► 

D3 



E 




t 


output 

corresponding 
to the input, 
from DO to D3 


AO, A1 



D0..D3 


E 



Y 


Table 3.22. Truth table for a multiplexer with four data inputs, 
from D 0 to D 3 \ two selection inputs, from A 0 to A/; an enable 
input, E\ one output, Y. 


E 

Aj 

Ao 

d 3 

d 2 

Di 

Do 

Y 

0 

X 

X 

d 3 

d 2 

d[ 

do 

0 

1 

0 

0 

d 3 

d 2 

di 

do 

do 

1 

0 

1 

d 3 

d 2 

d[ 

do 

d 3 

1 

1 

0 

d 3 

d 2 

di 

do 

d 2 

1 

1 

1 

d 3 

d 2 

di 

do 

d 3 

























Combinational circuits 


129 


Figure 3.23. Two example of a multiplexer with four data inputs. 


A0>- 
A1 >- 


D0>- 

D1 >- 

D2>- 

D3>- 


E>— 1 


Y 


D0>- 

D1 >- 

D2>- 

D3>- 


A0> 

A1 >—< 


7 


7 

1 












1 

1 






1 

1 








1 

1 

E>-J 


1 


O-^ Y 


Listing 3.24. Example with Verilog. 


module multiplexer_l_of_4 (Y, A, 

D, E); 

input [1:0] 

A; 


input [3:0] 
input E; 
output Y; 

// 

D; 


function flof4 (input [1:0] A, 

input [3:0] D, 


input E); 


if (E == 

1) 


begin 



case 

(A) 


0 : 

flof4 = D[0] ; 


1: 

flof4 = D[1] ; 


2 : 

flof4 = D[2] ; 


3: 

flof4 = D[3] ; 


endcase 


end 



else 


































































130 


Combinational circuits 


begin 

flof4 = 0; 
end 

endfunction 

// 

assign #8 Y = flof4 (A, D, E); 
endmodule 


Listing 3.25. Verilog gate level alternative code following the 
picture 3.23 on the left. 

module multiplexer_l_of_4 (Y, A, D, E); 
input [1:0] A; 
input [3:0] D; 
input E; 
output Y; 

wire wO, wl, w2, w3; 


assign 

#4 

wO 

= E & 

~A[0] 

& 

~A[1] 

& 

D[0] ; 

assign 

#4 

wl 

= E & 

A [ 0 ] 

& 

~A [ 1 ] 

& 

D[l] ; 

assign 

#4 

w2 

= E & 

~A [ 0 ] 

& 

A [ 1 ] 

& 

D[2] ; 

assign 

#4 

w3 

= E & 

A [ 0 ] 

& 

A [ 1 ] 

& 

D[3] ; 

assign 

#4 

Y 

= wO 

wl 

w2 

1 w3; 




endmodule 


Listing 3.26. Verilog gate level alternative code following the 
picture 3.23 on the right. 

module multiplexer_l_of_4 (Y, A, D, E); 
input [1:0] A; 
input [3:0] D; 
input E; 





Combinational circuits 


131 


output Y; 








wire [1:0] 


A; 






wire wO, wl. 

w2, 

w3; 





assign _A 

= 

~A; 






assign #4 

wO 

= E 

& A [ 0 ] 

& 

_A[1] 

& 

D[0] ; 

assign #4 

wl 

= E 

& A [ 0 ] 

& 

_A [ 1 ] 

& 

D[l] ; 

assign #4 

w2 

= E 

& _A[0] 

& 

A [ 1 ] 

& 

D[2] ; 

assign #4 

w3 

= E 

& A [ 0 ] 

& 

A [ 1 ] 

& 

D[3] ; 

assign #4 

Y 

= wO 

1 wl | 

w2 

1 w3; 



endmodule 









Common multiplexer integrated circuits are 74150, 74151 and 
74157 (see section u0.2). 

3.4 Multiplexer and demultiplexer with parallel I/O 

Multiplexers and demultiplexers might be required to work on data 
composed of more than a single bit. In that case, many multiplexers 
or demultiplexers are required, but joining the selection and enabling 
ports. The following figures show a demultiplexer and a multiplexer 
in a detailed version (on the left) and in a compact version with some 
wires grouped together (on the right). 



132 


Combinational circuits 


Figure 3.27. Demultiplexer with input and outputs composed of 
four value vectors. 


AO, A1 


4 

-A- 


DO, Dl, D2, D3 


>^3 


^^3 


2 


—^3 


Y0,0 Y0,1 Y0,2 Y0,3 


4 

-A- 


Y1,0 Yl,l Yl,2 Yl,3 

4 


■/ 


Y2,0 Y2,l Y2,2 Y2,3 


4 

-A- 


n Y3,0 Y3,l Y3,2 Y3,3 


4 






















































































Combinational circuits 



133 













134 


Combinational circuits 


Figure 3.28. Multiplexer with inputs and output composed of 
four value vectors. 

2 

A —7^ 


A0.A1 


D0,0 D0,1 D0,2 DO,3 


4 

~7^~ 


D1,0 Dl,l Dl,2 Dl,3 


4 

~7^~ 


D2,0 D2,l D2,2 D2,3 r . 


4 

~7^~ 


D3,0 D3,l D3,2 D3,3 


4 

~7^~ 


2 


/ 2 


2 

-7<- 


DOX 

Dl^~ 
D2-^ 
D3 ~7~ 


0 


i. 


7^Y 


YO Y1 Y2 Y3 


4 


Listing 3.29. Quad 2-to-4 demultiplexer example in Verilog. 


module demultiplexer_2_to_4_x4 (YO, Yl, Y2, Y3, A, 

D, E) ; 

input [1:0] A; 



























































































Combinational circuits 


135 



Listing 3.30. Quad l-of-4 multiplexer example in Verilog. 

module multiplexer_l_of_4_x4 (Y, A, DO, Dl, D2 

D3, E); 

input [1:0] A; 

input [3:0] DO, Dl, D2, D3; 

input E; 

output [3:0] Y; 

wire [1:0] _A; 

wire [3:0] wO, wl, w2, w3; 

assign _A = ~A; 

assign #4 wO = (E & _A[0] & _A[1])?D0:0; 

assign #4 wl = (E & A[0] & _A[1])?D1:0; 

assign #4 w2 = (E & _A[0] & A[1])?D2:0; 

assign #4 w3 = (E & A[0] & A[1])?D3:0; 

assign #4 Y = wO | wl | w2 | w3; 
endmodule 





136 

3.5 Binary encoder 


Combinational circuits 


A binary encoder is a combinational circuit having n output lines 
and 2 n input lines, where only an input line at a time can be asserted 
and the value obtained from the output reports the number of the 
asserted input line. The following examples show binary encoders 
with n equal to 1, 2 and 3. 

Table 3.31. Truth table for a binary encoder with two inputs and 
one output. 


D ! 

Do 

Y 0 

0 

1 

0 

1 

0 

1 


Figure 3.32. To obtain a binary encoder with two input lines it is 
enough to connect the second input line to the output. 

DO >- 


D1 >-YO 

Table 3.33. Truth table for a binary encoder with four input and 
two output ports. 


d 3 

d 2 

Dj 

Do 

Yj 

Y 0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

1 

0 

1 

0 

0 

1 

0 

1 

0 

0 

0 

1 

1 








Combinational circuits 


137 


Figure 3.34. Binary encoder with four input and two output ports. 
The first input line is not connected, because if it is asserted the 
output should be zero anyway. 

DO >- 


D1 > 

D2> 

D3> 


O-^ YO 



^ Y1 


Table 3.35. Truth table for a binary encoder with eight input and 
three output ports. 


d 7 

De 

d 5 

d 4 

Ds 

Lh 

Lh 

Do 

y 2 

Yj 

Yo 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

1 

0 

0 

0 

0 

0 

1 

0 

0 

0 

1 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

1 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

1 

0 

1 

0 

1 

0 

0 

0 

0 

0 

0 

1 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 




138 


Combinational circuits 


Figure 3.36. Binary encoder with eight input and three output 
ports. 

D0>- 



Listing 3.37. Binary encoder example, with eight input and three 
output ports, written in Verilog. This solution is different from 
the picture 3.36, because if the input value is not as expected, the 
encoded output is zero. 





Combinational circuits 


139 


// 


function [2:0] be8to3 (input [7:0] D); 

case 

(D) 

1 

be8to3 = 0; 

2 

be8to3 = 1; 

4 

be8to3 = 2; 

8 

be8to3 = 3; 

16 

be8to3 = 4; 

32 

be8to3 = 5; 

64 

be8to3 = 6; 

128 

be8to3 = 7; 

default: be8to3 = 0; 

endcase 

endfunction 

// 


assign #6 Y = be8to3 (D); 

endmodule 



Listing 3.38. Binary encoder example describing the gates in pic- 
ture 3.36. _ 

module binary_encoder (Y, D); 
input [7:0] D; 
output [2:0] Y; 


assign 

#6 

Y [ 0 ] 

= D [ 1 ] 

1 D [ 3 ] 

1 D [ 5 ] 

1 D [ 7 ] ; 

assign 

#6 

Y [ 1 ] 

= D [ 2 ] 

1 D [ 3 ] 

1 D [ 6 ] 

1 D [ 7 ] ; 

assign 

#6 

Y [ 2 ] 

= D [ 4 ] 

1 D [ 5 ] 

1 D [ 6 ] 

1 D [ 7 ] ; 


endmodule 





« 


140 

3.6 Priority encoder 


Combinational circuits 


The priority encoder is a binary encoder that allows the assertion of 
every input line, giving on the output the number corresponding to 
the asserted input having priority above all the others. In that case it 
is also allowed to have no input line asserted, thus there might be an 
additional output port that is asserted only when there is at least an 
input line asserted. 

Table 3.39. Truth table for a priority encoder with four input 
ports. The asserted input with the lower index has priority above 
the others, therefore the letter ‘X’ is used to show an unspecified 
value for the other lower priority input ports. The output port GS 
(group select) is asserted when at least an input line is asserted. 


d 3 

d 2 

Dt 

Do 

GS 

Yt 

Y 0 

0 

0 

0 

0 

0 

X 

X 

X 

X 

X 

1 

1 

0 

0 

X 

X 

1 

0 

1 

0 

1 

X 

1 

0 

0 

1 

1 

0 

1 

0 

0 

0 

1 

1 

1 











142 


Combinational circuits 


Listing 3.42. Example with Verilog. 


module priority_ 

encoder 

CM 

1 

O 

4-> 

1 

1 

(Y f 

GS , D); 

input [3: 

0] D; 





output [1 

: 0] Y 

• 

r 




output GS 

// 

• 

r 





function 

[1:0] 

f 4to2 

(input 

[3:0] 

D) ; 

if (D & 

1) 





f 4to2 

= 0; 





else if 

(D & 

2) 




f 4to2 

= i; 





else if 

(D & 

4) 




f 4to2 

= 2; 





else if 

(D & 

8) 




f 4to2 

= 3; 





else 






f 4to2 

= 0; 





endfunction 





// 

assign #8 

Y = 

f 4to2 

(D) ; 



assign #8 

GS = 

D[0] | 

D[l] 1 

D[2] 

1 D [ 3 ] ; 

endmodule 







Listing 3.43. Verilog gate level alternative code following the 
picture 3.40. 

module priority_encoder_4_to_2 (Y, GS, D) ; 
input [3:0] D; 
output [1:0] Y; 
output GS; 




Combinational circuits 


143 


wire wO 


wl, w2; 





assign 

#4 

wO = ~D [ 0 ] 

& D [ 1 ] ; 




assign 

#4 

wl = ~D [ 0 ] 

& ~D[1] 

& 

D[2] ; 


assign 

#4 

w2 = ~D [ 0 ] 

& ~D [ 1] 

& 

~D[2] 

& D[3] ; 

assign 

#4 

Y[0] = wO 

w2; 




assign 

#4 

Y[1] = wl 

| w2; 




assign 

#8 

GS = D[0] 

1 D [ 1 ] | 

D[2] | 

D[3] ; 

endmodule 








Listing 3.44. Verilog gate level alternative code following the 
picture 3.41. 


module priority_encoder 

CM 

1 

O 

4-> 

1 

1 

(Y, GS, 

D) ; 

input [3: 

0] D; 




output 

[1 

: 0 ] Y; 




output 

GS 

• 

r 




wire [2 

:0] _D; 




wire wO 


wl, w2; 




assign 

_D 

= ~D; 




assign 

#4 

wO = _D [ 0] 

& D [ 1 ] ; 



assign 

#4 

wl = _D[0] 

& _D [ 1 ] 

& D [ 2 ] ; 


assign 

#4 

w2 = _D [ 0] 

& _D [ 1 ] 

& _D [ 2 ] 

& D[3] ; 

assign 

#4 

Y[0] = wO 

| w2; 



assign 

#4 

Y[1] = wl 

w2; 



assign 

#8 

GS = D [0] | 

D[l] | 

D[2] | 

D[3] ; 

endmodule 







A common priority encoder circuit is 74148 (see i 1.3.1). 




144 


Combinational circuits 


3.7 Logic units 


Using a multiplexer it is possible to obtain easily a logic unit for 
the common logic operations, selecting the desired one through a 
function value. For example, it might be possible to build the circuit 
that does the task shown in the following figure: 

2 


y 


4 



f 

-► 

A 


logic L 

-► 

B 



fj f output 

0 0 A AND B 

0 1 A OR B 

1 0 A XORB 

1 1 NOT B 


Figure 3.46. Logic unit implementation example with four op¬ 
tions. 


A> 


B> 



> L 


Logic units like this one are useful if the input lines (A and B) are 
multi-bit sized. To obtain this it suffice to place in parallel more 
single-bit units with the function control inputs if) connected to- 



































Combinational circuits 


145 


gether. 

Figure 3.47. More logic units can be connected in parallel, to 
operate on multi-bit values. The diagram on the right, below, is 
a compact representation of the same circuit. 



b 


L0..L3 






















































146 


Combinational circuits 


f 1 f output 

0 0 A AND B 

0 1 A OR B 

1 0 A XORB 

1 1 NOT B 


2 



3.8 Shift and rotation 

The bit shift is an important binary operation that can be imple¬ 
mented with a combinational circuit. There is an ordered group of 
n inputs, starting from 0 to n- 1, a group of n outputs ordered in 
the same way and there might be a carry input and a carry output. 
Often it is considered the shift of a single binary digit, because more 
binary digits might be shifted repeating the operation. The shift and 
rotation operations require to specify the direction: left or right. 

The easiest kind of shift is the logic shift , which moves the bits left 
or right, losing the most significant bit or the least significant one, 
inserting a zero at the opposite side. The following figures imple¬ 
ment the logic shift and the other types of shifts and rotations, using 
multiplexers, where the connection to the ground means a fixed 0 
input. 

1110 original value 1110 original value 

110 0 left logic shift 0 111 right logic shift 





























Combinational circuits 


147 


Figure 3.49. 4-digit left and right logic shift, with 2-input multi¬ 
plexers. The shift direction is established by the value received 
from the / input. The shift loses a binary digit from one side and 
gets 0 (zero) from the opposite side. 


D f 

v v 



Listing 3.50. 4-digit logic shift: example with Verilog. 


module logic_ 

shift_4 

(S, D, 

f); 

input [3:0] 

D; 




input f; 





output [3:0 

] S; 

l 

f 



// 





function [3 

: 0 ] 

lsh 

(input 

[3:0] D, input f); 

if (f == 

0) 




lsh = D 

<< 

i; 




















































148 


Combinational circuits 


else 

lsh = D >> 1; 
endfunction 

// 

assign #6 S = lsh (D, f); 
endmodule 


The other Verilog examples of the section describe only the gate 
logic level, assuming that the 2-input multiplexers are implemented 
as the following figure shows: 

01 99 

v v 



Y 


Listing 3.52. 4-digit logic shift: detailed gate level implementa¬ 
tion. 


module logic_shift_4 (S, D, f); 

input 

[3:0] D; 

input 

f; 

output 

[3:0] S; 

wire _ 

f = ~f; 





















Combinational circuits 


149 


// 

assign #6 

S [0] 

= (D [ 1 ] 

& f) ; 



assign #6 

s [1] 

= ( (D [ 2 ] 

& f) 1 

(D[0] 

& _f)); 

assign #6 

s [2 ] 

= ( (D [ 3 ] 

& f) 1 

(D [ 1 ] 

• < 

1 

assign #6 

S [3] 

= (D [ 2 ] 

& _f); 



endmodule 







The arithmetic shift is made in the same way as the logic one, with 
the exception that the right shift must keep the sign unaltered. In 
practice, when doing an arithmetic right shift, the digit inserted on 
the most significant position is the same as the original one. This 
kind of shift is called ‘arithmetic’ because the result is the same as 
the multiplication and division by two. However it should be noticed 
that the left shift might produce an overflow, corresponding to the 
lost of the original sign. 

1110 original value 1110 original value 

110 0 left arithmetic shift 1111 right arithmetic shift 


0 110 original value 
110 0 left arithmetic shift (*) 


0 110 original value 
0 0 11 right arithmetic shift 


10 10 original value 
0 10 0 left arithmetic shift (*) 


10 10 original value 
110 1 right arithmetic shift 


(*) when shifting to the left, a sign inversion might be produced (overflow) 



150 


Combinational circuits 


Figure 3.54. 4-digit, left and right arithmetic shift, using 2-input 
multiplexers. The shift direction is defined by the value received 
from the / input. 


D f 

v v 



Listing 3.55. 4-digit arithmetic shift: detailed gate level imple- 
mentation. _ 

module arithmetic_shift_4 (S, D, f); 
input [3:0] D; 
input f; 
output [3:0] S; 
wire _f = ~f; 

// 

assign #6 S[0] = (D[l] & f); 

assign #6 S[l] = ((D[2] & f) | (D[0] & _f) ) ; 
























































Combinational circuits 


151 


assign #6 

S [2 ] 

= ( (D [3] 

& f) 

(D [ 1 ] 

& _f)); 

assign #6 

endmodule 

S [3] 

= ( (D [ 3 ] 

& f) 

(D[2] 

& _f)); 


The rotation is a shift operation where the binary digit lost from one 
side is inserted at the opposite side, either on the left or the right 


rotation. 

0 1 1 

0 

original value 

0 

1 

1 

0 

original value 

1 

1 

0 

0 

left rotation 

0 

0 

1 

1 

right rotation 

1 

1 

0 

0 

original value 

0 

0 

1 

1 

original value 

1 

0 

0 

1 

left rotation 

1 

0 

0 

1 

right rotation 

1 

0 

0 

1 

original value 

1 

0 

0 

1 

original value 

0 

0 

1 

1 

left rotation 

1 

1 

0 

0 

right rotation 





152 


Combinational circuits 


Figure 3.57. 4-digit rotation, with 2-input multiplexers. The ro¬ 
tation direction is specified by the value received from the input 

/• 


D f 

v v 



Listing 3.58. 4-digit rotation: detailed gate level implementation. 

module rotation_4 (S, D, f); 
input [3:0] D; 
input f; 
output [3:0] S; 
wire _f = ~f; 

// 

assign #6 S[0] = ((D[l] & f) | (D[3] & _f)); 




























































Combinational circuits 


153 


assign #6 

S[l] 

= ( (D [2 ] 

& 

f) 1 

(D [ 0 ] 

& 

_f)); 

assign #6 

S [2 ] 

= ( (D [3] 

& 

f) 1 

(D[l] 

& 

_f)); 

assign #6 

endmodule 

S [3] 

= ( (D [ 0 ] 

& 

f) 1 

(D[2] 

& 

_f)); 


The rotation with carry uses the previous carry for the digit inserted 
at one side and saves the removed digit from the opposite side as the 
new value for the carry (after the rotation). 

1 110 original value ... " 1 original carry 

! 1 10 1 left rotation ^ 1 final carry 


1110 ... original value 

\ . 

1111 right rotation 


1 

0 


original carry 
final carry 









154 


Combinational circuits 


Figure 3.60. 4-digit input, rotation with carry, using 2-input mul¬ 
tiplexers. The rotation direction is specified by the value received 
from the / input. 



3.9 Addition 

The binary addition, made in the same common way used for the 
decimal numbering system, does not generate a carry higher than 1. 
It can be verified through the following table. 




































































Combinational circuits 


155 


Table 3.61. Binary addition. 


first 

addend 

second 

addend 

previous 
carry 
(carry in) 

generated 

carry 

(carry out) 

result 

0 

0 

0 

0 

0 

0 

0 

1 

0 

1 

0 

1 

0 

0 

1 

0 

1 

1 

1 

0 

1 

0 

0 

0 

1 

1 

0 

1 

1 

0 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 


Therefore, the combinational circuit that can do the binary addition 
must have three input (first addend, second addend, carry in) and two 
output ports (result, carry out). 


Figure 3.62. Adder block diagram. The abbreviation FA stands 
for full-adder. 


addends 






A 

B 



Co 

FA 

Ci 


◄- 




< 

V 

D 








previous carry 
(carry in) 


A B 




generated carry mm | 

(carry out) g 

It is custom to consider the full-adder (the one shown above) to be 




156 


Combinational circuits 


made of two smaller modules, known as half-adders. The half-adder 
is a combinational circuit with two input ports, corresponding to the 
two addends, and two output ports, corresponding to the sum and the 
generated carry; in practice, the half-adder has no previous carry. 


Table 3.63. Truth table for a half-adder: A and B are the addends, 
S and Co are the sum and the carry outputs. 


A 

B 

Co 

s 

0 

0 

0 

0 

0 

1 

0 

1 

1 

0 

0 

1 

1 

1 

1 

0 


It can be easily guessed that the half-adder sum can be obtained with 
an XOR gate and that the carry output requires an AND gate. 


Figure 3.64. Half-adder block diagram and implementation ex¬ 
ample. The abbreviation HA stands for half-adder. 



4 

4 


A 

B 

4 - 

Co 

HA 




( 

V 

3 




4 


A> 
B > 



)... Co 


To obtain a full-adder from half-adders, it is necessary to sum also 
the input carry. 





Combinational circuits 


157 


Figure 3.65. Full-adder block diagram, obtained with two half¬ 
adders. 

Ci>-1 I-1 








158 


Combinational circuits 


Figure 3.66. Full-adder alternative implementations, with the 
help of Karnaugh maps. 


A 

B 

Ci 

Co 

s 

0 

0 

0 

0 

0 

0 

0 

1 

0 

1 

0 

1 

0 

0 

1 

0 

1 

1 

1 

0 

1 

0 

0 

0 

1 

1 

0 

1 

1 

0 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 














































Combinational circuits 


159 



Co 


To be useful, the addition should be applied to binary addends com¬ 
posed of more than a single digit, therefore it is necessary to as¬ 
semble in parallel some adders, passing properly the carry from the 
less significant digit to the next more significant one, digit by digit. 
This method of carry propagation is known as ripple-carry and it is 
illustrated by the following figure. 



160 


Combinational circuits 


Figure 3.67. Ripple-carry 4-digit adder. On the right is shown a 
compact representation, but it is not specified there in what way 
the carry is propagated. 


A B Ci 

V V V 



s 

The described adder works correctly with the addition of positive 
and negative numbers, when the negative numbers are represented 
as 2’s complement of the positive equivalent value. 




























































Combinational circuits 


161 


Listing 3.68. A simple Verilog implementation of a 4-bit adder. 

module adder_4 (Co, S, A, B, Ci); 
input [3:0] A, B; 
input Ci; 
output Co; 
output [3:0] S; 

// 

assign #30 {Co, S} = A + B + Ci; 
endmodule 


Listing 3.69. Gate level implementation of a 4-bit adder with 
ripple-carry. 

module adder_4 (Co, S, A, B, Ci); 
input [3:0] A, B; 
input Ci; 
output Co; 
output [3:0] S; 
wire [4:0] C; 

// 

function add (input A, input B, input Ci); 

add = A A B A Ci; 
endfunction 

// 

function carry (input A, input B, input Ci); 

carry = A&B|A&Ci|B&Ci; 
endfunction 

// 

assign #0 C[0] = Ci; 

assign #6 C[l] = carry (A[0], B[0], C[0]); 




162 


Combinational circuits 


assign 

#6 

C[2] = carry (A[1] 

, B [ 1 ] 

, C [ 1 ] ) ; 

assign 

#6 

C[3] = carry (A[2] 

, B [ 2 ] 

, C [ 2 ] ) ; 

assign 

#6 

C[4] = carry (A[3] 

, B [ 3 ] 

, C [ 3 ] ) ; 

// 






assign 

#5 

S[0] = add 

(A [ 0 ] , 

B [ 0 ] , 

C[0]) ; 

assign 

#5 

S[1] = add 

(A [ 1 ] , 

B [ 1 ] , 

C[l]) ; 

assign 

#5 

S[2] = add 

(A [ 2 ] , 

B [ 2 ] , 

C [ 2 ] ) ; 

assign 

// 

#5 

S[3] = add 

(A [ 3 ] , 

B [ 3 ] , 

C [ 3 ] ) ; 

assign 

#0 

Co = C [4]; 




endmodule 






3.10 Subtraction 

« 


The basic building block for the subtraction is the half-subtractor. 
As the order of the operands is significant, it is necessary to distin¬ 
guish between minuend and subtrahend, therefore all the following 
examples will use this notation: D=M-S. 


Table 3.70. Half-subtractor truth table. 


M 

s 

B 0 

D 

0 

0 

0 

0 

0 

1 

1 

1 

1 

0 

0 

1 

1 

1 

0 

0 





Combinational circuits 


163 


Figure 3.71. HS: half-subtractor, 
minuend 


M > 
S> 



difference 

> D 

^ Bo 


subtrahend borrow 

Instead of the carry output there is the borrow , which is as¬ 
serted when the subtrahend is greater than the minuend. The full- 
subtractor has an additional borrow input coming from a previ¬ 
ous digit. To build the full-subtractor it is possible to use two half¬ 
subtractors, where the second one subtracts from the result of the 
first one the borrow input. 


Table 3.72. Full-subtractor truth table. 


M 

s 

Bi 

B„ 

D 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

0 

1 

0 

1 

1 

0 

1 

1 

1 

0 

1 

0 

0 

0 

1 

1 

0 

1 

0 

0 

1 

1 

0 

0 

0 

1 

1 

1 

1 

1 




164 


Figure 3.73. FS: full-subtractor. 



borrow in 
Bi>- 


M 

v \/ 
Bo —\ - 

D 


Combinational circuits 






Combinational circuits 


165 


Figure 3.74. Full-subtractor alternative implementation, with the 
help of Karnaugh maps. 


M 

s 

Bi 

Bo 

D 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

0 

1 

0 

1 

1 

0 

1 

1 

1 

0 

1 

0 

0 

0 

1 

1 

0 

1 

0 

0 

1 

1 

0 

0 

0 

1 

1 

1 

1 

1 













































166 


Combinational circuits 


M> 

S> 

Bi > 



D 


Bo 


Just like in the addition, it is possible to build a chain of full- 
subtractors. 



Combinational circuits 


167 


Figure 3.75. 4-bit subtraction. 




D 


Listing 3.76. A simple Verilog implementation of a 4-bit subtrac- 
tor. _ 

module subtractor_4 (Bo, D, M, S, Bi); 
input [3:0] M, S; 
input Bi; 
output Bo; 




























































168 


Combinational circuits 


output [3:0] D; 

// 

assign #30 {Bo, d} = M - S - Bi; 
endmodule 


Listing 3.77. Gate level implementation of a 4-bit subtractor. 

module subtractor_4 (Bo, D, M, S, Bi); 
input [3:0] M, S; 
input Bi; 
output Bo; 
output [3:0] D; 
wire [4:0] B; 

// 

function sub (input M, input S, input Bi); 

sub = M A S A Bi; 
endfunction 

// 

function borrow (input M, input S, input Bi); 

borrow = ~M&Bi|S&Bi|~M&S; 
endfunction 

// 


assign 

#0 

B [ 0 ] 

= Bi; 




assign 

#6 

B [ 1 ] 

= borrow 

(M[0] , 

S[0] , 

B [ 0 ] ) ; 

assign 

#6 

B [ 2 ] 

= borrow 

(M [ 1 ] , 

S[l] , 

B [ 1 ] ) ; 

assign 

#6 

B [ 3 ] 

= borrow 

(M[2] , 

S[2] , 

B [ 2 ] ) ; 

assign 

#6 

B [ 4 ] 

= borrow 

(M [ 3 ] , 

S [3] , 

B [ 3 ] ) ; 


// 

assign #5 D[0] = sub (M[0], S[0], B[0]); 
assign #5 D[l] = sub (M[l], S[l], B[l]); 




Combinational circuits 


169 


assign #5 

D[2] 

= sub 

(M [2] , S[2] , B[2] ) ; 

assign #5 

// 

D[3] 

= sub 

(M [ 3] , S[3], B [ 3]); 

assign #0 

Bo = 

B [ 4 ] ; 


endmodule 





3.11 Addition and subtraction together 

The full-adder works correctly for the sum of positive and negative 
numbers, when the negative ones are represented by the 2’s com¬ 
plement method, therefore, to transform an adder into a subtractor, 
it is enough to calculate the 2’s complement for the subtrahend. To 
achieve the result it is more convenient to invert all the subtrahend 
bits (l’s complement) and also the carry input, which now assumes 
the role of borrow input. To obtain coherently a borrow output, even 
the carry output should be inverted. 



170 


Combinational circuits 


Figure 3.78. 4-digit subtractor: in that case it is calculated A-B. 
On the right side it is shown a compact representation of the same 
thing. 



S 

The addition and subtraction can be combined with XOR gates, in¬ 
stead of inverters, with a function control input that specifies the 
action to take. 













































































Combinational circuits 


171 


Figure 3.79. 4-digit addition or subtraction. 




































































172 


Combinational circuits 


A B f 



Listing 3.80. Gate level implementation of a 4-bit adder and sub- 

tractor. _ 

module addsub_4 (CoBo, S, f, A, B, CiBi); 
input [3:0] A, B; 
input f, CiBi; 
output CoBo; 
output [3:0] S; 
wire [4:0] C; 

// 

function add (input A, input B, input C); 

add = A A B A C; 
endfunction 

// 

function carry (input A, input B, input C); 

carry = A&B|A&C|B&C; 
endfunction 





















































Combinational circuits 


173 


// 






assign 

#0 

C[0] 

= CiBi A f; 



assign 

#6 

C[l] 

= carry (A[0] 

, B [ 0 ] A 

f, C [ 0 ] ) ; 

assign 

#6 

C [ 2 ] 

= carry (A[l] 

, B[ir 

f, C[ 1 ] ) ; 

assign 

#6 

C [ 3 ] 

= carry (A[2] 

, B [ 2 ] A 

f, C[2] ) ; 

assign 

// 

#6 

C [ 4 ] 

= carry (A[3] 

, B [ 3 ] A 

f, C[3] ) ; 

assign 

#5 

s [0] 

= add (A[ 0 ] , 

B [ 0 ] A f, 

C[0]) ; 

assign 

#5 

s [1] 

= add (A[1], 

B[l] A f, 

C[l] ) ; 

assign 

#5 

s [2 ] 

= add (A[2], 

B [ 2 ] A f, 

C [ 2 ] ) ; 

assign 

// 

#5 

s [3] 

= add (A[3], 

B [ 3 ] A f, 

C [ 3 ] ) ; 

assign 

#0 

CoBo 

= C [4] A f; 



endmodule 






3.12 Carry lookahead 

The addition with a significant amount of bits, using the ripple-carry 
method of carry propagation is very slow. To accelerate the opera¬ 
tion, every digit requires to get a valid previous carry in the shortest 
possible time, with the method known as carry-lookahead. In the 
following expressions, the variables A,-, B, and C* represent the two 
addends and the carry input of the stage i (the digit taken into consid¬ 
eration); therefore, the carry generated from this stage is represented 
by the variable C i+1 . 



174 


Combinational circuits 


Figure 3.81. Alternative ways to calculate the output carry. 



The figure above shows that the carry can be synthesized in various 
ways, one of which uses the XOR operator. Two equivalent expres¬ 
sions are chosen from the above picture: 


Ci+i = = AiBi+(Ai®Bi)Ci 

From these expressions, two new variables are defined, G* and P i9 
which stand for generation and propagation , so that the carry Cm 


































Combinational circuits 


175 


is defined by the value of G*, P t and C*. 

Ci+i = Gi+PiCi 

It is obvious that G, is equivalent to AjB,, whereas P t can be consid¬ 
ered either equal to A ,•+/?,• or to A*©Z?*. If the first generated carry 
(Ci) can be obtained as Ci=Go+PoCo, the second one is obtained as 
C 2 =Gi+Pi(Go+CoPo ), and the same way all the subsequent ones can 
be determined. The solutions for the first four carries follow: 

Ci = Go+PoCo 

C 2 = Gi+PiCi 

C 2 = Gi+Pl(Go+PoCo) 

C 2 =Gi+PiGo+PiPoG) 

C 3 = G 2 -\-p2C 2 

C3 = G f 2+P2(Gi+PiG 0 +PiP 0 Co) 

G 3 = Gs+PsGi+PsPiGo+PsPiPo^o 

G 4 = G3+P3C3 

G 4 = G 3 +P3(G2+P2Gi+P 2 PiGo+P2PiPoCo) 

C4 = G3+P3G2+P3P2G1+P3P2P1G0+P3P2P1P0C0 
To simplify the expressions, P n and G n are defined in the following 
way: 

Pn = Pn-lPn-lPn-l “ • P\Pq 

G n = G n _i-|-Pn-lG n _ 2 +Pn- 2 Pn-l^n -3 + * * *+Pn- 2 Pn-l * * * PlGo 
Having defined P n and G„, the carry C n can be defined as: 

C n = Gn+Pn^O 



176 


Combinational circuits 


The following figure shows a lookahead generator : in that case it 
is a combinational circuit that determines the carries of four binary 
digits, starting from the initial carry and the values from B 3 , 0 and 
G 3 . , 0 , as described by the equations that define this relation. The draw 
contains also the logic necessary to determine the value of B 4 and 
G 4 , which can be useful to connect together more modules of this 
type. 



Combinational circuits 


Figure 3.87. Diagram for the determination of four carries, start¬ 
ing from the initial one (Co) and from the values of P t and G/, as 
described by the logic equations. 


CO > 

PO > 
GO > 


PI > 
G1 > 


P2 > 
G2 > 


P3 > 
G3 > 



Cl 

C2 

C3 

C4 

P4 

G4 


= GO+PO-CO 


= Gl+Pl- G0+P1 -PO-CO 


= G2+P2-G1+P2-P1-G0+ 
+P2-P1-P0-C0 


= G3+P3-G2+P3-P2-G1+ 
+P3-P2-P1-G0+ 

+P3-P2-P1-P0-C0 


= P3P2-P1P0 

= G3+P3G2+P3P2-G1+ 
+P3-P2-P1-G0 






178 


Combinational circuits 


The adder that produces the values G and P can be synthesized with¬ 
out the carry output, as this value is determined by the above mod¬ 
ule. There are two alternative solutions, because the P value can be 
defined either as Ai+Bi or A,®/?,-. 

Figure 3.88. Addition modules with P and G outputs, but without 
the carry output. 



The following figure shows a 4-digit adder, made of the previous 
modules of addition and carry-lookahead. 




























180 


Combinational circuits 


An adder, like the one shown above, can be connected with other 
modules to increase the number of digits, without adding too much 
delay. In the following figure, the module SUM4 corresponds to the 
one described in figure 3.89, where only the last two carries are con¬ 
nected to the outside (the last two carries will be necessary to test 
if there is an overflow); the module CLH4 corresponds to the one 
described in figure 3.87, which is used to connect the addition mod¬ 
ules. 



Combinational circuits 


181 


Figure 3.90. 20-bit adder, made of 4-bit modules connected to¬ 
gether. 


s 



C19 C20 














































































182 


Combinational circuits 


Listing 3.91. Fast 4-digit adder, Verilog gate level implementa¬ 
tion. 


module SUM4 

(C 4, 

C2 

>, P4, G4, S, A, B, CO); 

input 
input ( 

[3:0] A, 

30; 

B; 


output 

C3, 

C4, 

P4 

r G4; 

output 

[3: 

0] s 

• 

r 


wire [4:0] 

// 

c. 

Pf 

G; 

assign 

#0 

C[0] 

= 

CO; 

assign 

#5 

S[0] 

= 

A[0] A B[0] A C [0] ; 

assign 

#5 

S[1] 

= 

A[l] A B[1] A C [1] ; 

assign 

#5 

S [ 2 ] 

= 

A[2] A B[2] A C [2]; 

assign 

// 

#5 

S [ 3 ] 

—— 

A [3] A B [3] A C [3] ; 

assign 

#5 

P[0] 

= 

A [ 0 ] | B [ 0 ] ; 

assign 

#5 

P[l] 

= 

A [ 1 ] | B [ 1 ] ; 

assign 

#5 

P [ 2 ] 

= 

A [2 ] |B[2] ; 

assign 

#5 

P [ 3 ] 

= 

A [3] | B [3] ; 

assign 

// 

#6 

P[4] 

—— 

P [3] &P [2] &P [1] &P [0] ; 

assign 

#5 

G[0] 

= 

A[0]&B [ 0]; 

assign 

#5 

G[l] 

= 

A[1]&B [ 1]; 

assign 

#5 

G [ 2 ] 

= 

A[2] &B [2] ; 

assign 

#5 

G [ 3 ] 

= 

A[3]&B [3] ; 

assign 

// 

#7 

G [ 4 ] 


G[3]|P[3]&G[2]|P[3]&P[2]&G[1] 

P [3] &P [2] &P [1] &G [ 0 ] ; 

assign 

#7 

C[l] 

= 

G [ 0 ] 1 P [ 0 ] & C [ 0 ] ; 



Combinational circuits 


183 


assign 

#7 

C [ 2 ] 

= G[l]|P[1]&G[0]|P[1]&P[0]&C[0]; 

assign 

#7 

C [ 3 ] 

= G[2]|P[2]&G[1]|P[2]&P[1]&G[0] 




P [2] &P [1] &P [0] &C [0] ; 

assign 

#7 

C [ 4 ] 

= G[3]|P[3]&G[2]|P[3]&P[2]&G[1] 




|P [3] &P [2] &P [1] &G [ 0 ] 




| P [3] &P [2] &P [1] &P [0] &C [0] ; 

// 




assign 

#0 

C4 = 

C [ 4 ] ; 

assign 

#0 

C3 = 

C [ 3 ] ; 

assign 

#0 

P4 = 

P [ 4 ] ; 

assign 

#0 

G4 = 

G [ 4 ] ; 

endmodule 




A common 4-bit fast adder circuit is the 7483 (see il .4. 1) and a com¬ 
mon lookahead-generator circuit is the 74182 (see i 1.4.5). 

3.13 Increment and decrement 

To increment a value by 1, it is not necessary to use the full addition 
circuit, because there is only one input value and a carry input. This 
kind of circuit might be implemented as a half-adder chain (figure 
3.64): 



184 


Combinational circuits 


IN INC 

V V 



/ 

/ 

V 


OUT 

The same solution might be applied if it is necessary to decrement 
value by 1, using half-subtractors (figure 3.71): 
















































Combinational circuits 


IN 

V 


DEC 

V 


185 




V 


4 


OUT 

Increment and decrement implemented as in the previous figures, 
might require a relative long time to be completed, so a kind of carry- 
lookahead method should be applied to speed up the process. 
















































186 


Combinational circuits 


Figure 3.94. Fast increment: when Ci is asserted, the value re¬ 
ceived from IN is returned through OUT incremented by 1, oth¬ 
erwise it is reproduced unchanged. 



Y 

OUT 























































Combinational circuits 


187 


Figure 3.95. Fast decrement: when Bi is asserted, the value re¬ 
ceived from IN is returned through OUT decremented by 1, oth¬ 
erwise it is reproduced unchanged. 



Listing 3.96. Fast increment: gate level implementation. 

module INC4 (OUT, Co, IN, Ci) ; 
input [3:0] IN; 
input Ci; 
output [3:0] OUT; 



















































188 


Combinational circuits 


output Co; 
wire [4:0] C; 

// 

assign C[0] = Ci; 
assign Co = C[4]; 

// 


assign 

#6 

C[ 

1] = 

= IN[0] & 

Ci 

• 

r 



assign 

#8 

C[ 

2] = 

= IN[1] & 

IN 

[0] 

& 

Ci; 

assign 

#10 

C[ 

3] = 

= IN [ 2] & 

IN 

[i] 

& 

IN [0] 

assign 

#12 

C[ 

4] = 

= IN [ 3 ] & 

IN 

[2] 

& 

IN [ 1 ] 





& IN [ 0 ] 

& 1 

Ci; 



// 









assign 

#8 

OUT 

[0] 

= IN[0] ' 

' C 

[0] 

• 

r 


assign 

#8 

OUT 

[1] 

= IN[1] 7 

' C 

[1] 

• 

f 


assign 

#8 

OUT 

[2] 

= IN [2] ' 

' c 

[2] 

• 

r 


assign 

#8 

OUT 

[3] 

= IN [3] 7 

N c 

[3] 

• 

f 



// 

endmodule 


Listing 3.97. Fast decrement: gate level implementation. To save 
inverters, the internal wire _IN 3 „o holds the inverted input data 

(m. _ 

module DEC4 (OUT, Bo, IN, Bi) ; 
input [3:0] IN; 
input Bi; 
output [3:0] OUT; 
output Bo; 
wire [4:0] B; 
wire [3:0] _IN; 





Combinational circuits 


189 


// 







assign 

B[0] = Bi 

• 

r 




assign 

Bo 

= B [ 4 ] 

• 

r 




assign 

// 

#2 

_IN = 

-IN; 




assign 

#6 

B [ 1 ] 

= _IN [ 0 ] 

& 

Bi; 


assign 

#8 

B [ 2 ] 

= _IN[1] 

& 

_IN[0] 

& Bi; 

assign 

#10 

B [ 3 ] 

= _IN [ 2 ] 

& 

_IN[1] 

& _IN[0] & Bi; 

assign 

#12 

B [ 4 ] 

= _IN[3] 

& 

_IN[2] 

& _IN[1] 




& _IN[0] 

& Bi; 


// 







assign 

#8 

OUT[0] 

= IN[0] 

A 

B [ 0 ] ; 


assign 

#8 

OUT[1] 

= IN[1] 

A 

B [ 1 ] ; 


assign 

#8 

OUT[2] 

= IN[2] 

A 

B [ 2 ] ; 


assign 

// 

#8 

OUT[3] 

= IN[3] 

A 

B [ 3 ] ; 


endmodule 







3.14 2 , s complement 

To change the sign of an integer binary number, it is necessary a 
circuit that calculates the 2’s complement. To obtain the 2’s comple¬ 
ment it is required to calculate the l’s complement (bit inversion), 
adding 1. 



190 


Combinational circuits 


Figure 3.98. 2’s complement calculation, corresponding to the 
sign inversion of an 4-bit integer number. 


IN minus 

V V 



I 1 


OUT 

The example in the above figure shows that the input data is inverted 
(negated) if the input minus is asserted, but the same minus value is 
added, producing the final 2’s complement. If otherwise the minus 
input is not asserted, the input data is not changed and the output 
result remains the same. 

The sign inversion might be calculated with a shorter delay if the in¬ 
crement is obtained with a carry-lookahead method, as it is described 
in the previous section. The following figure shows a simplified dia- 






















































Combinational circuits 


191 


gram where INC is the incrementing module that might be designed 
with a fast carry calculation: 


minus 

V 



OUT 


3.15 Multiplication 

The binary multiplication is a process that requires the addition and 
the bit shifting. To operate correctly on signed integers, the calcu¬ 
lation should be done extending the input data to a double bit size; 
for example, if multiplicand and multiplier have only a 4-bit size, 
the result requires a size of up to 8 bits, but the calculation should 
be done as if also the input data were 8-bit wide. See the following 
examples. 











192 


Combinational circuits 


Figure 3.100. signed and unsigned 4-bit multiplication. 


integer multiplication 
without sign 

OOOOlOllx 
00001101 = 
00001011 + 
00000000 + 
00101100 + 
01011000 + 
00000000 + 
00000000 + 
00000000 + 
00000000 = 
10001 1 1 1 


negative multiplicand, 
positive multiplier 

1 1 1 1 lOllx 
00000101 = 
1 1 1 11011 + 
00000000 + 
1 1101100 + 
00000000 + 
00000000 + 
00000000 + 
00000000 + 
00000000 = 
11100111 


positive multiplicand, 
negative multiplier 

OOOOOlllx 
111 11101 = 
00000111 + 
00000000 + 
00011100 + 
00111000 + 
011 10000 + 
11 100000 + 
11000000 + 
10000000 = 
11101011 


negative multiplicand, 
negative multiplier 

1111 lOllx 
111 11101 = 
111 11011 + 
00000000 + 
1 1101100 + 
11011000 + 
101 10000 + 
01 100000 + 
11000000 + 
10000000 = 
00001 1 1 1 


In the above figure, the first example on the left shows the multiplica¬ 
tion of two unsigned values, which are extended using Os on the most 
significant side, before the multiplication is done. The other exam¬ 


ples are made with signed values and the negative ones are extended 


with Is on the most significant side, to keep the original negative 


sign, before the operation takes place. 


To resolve the problem with a combinational circuit, it is necessary 
to cross the multiplicand and multiplier values, verifying at every 
useful position the coincidence of values equal to 1. The following 
two figures should be overlapped, as they show the concept in two 
phases: the outputs from the AND gates must be added vertically to 
generate the product. 










Combinational circuits 


193 


Figure 3.101. Intersection between multiplicand and multiplier, 
using AND gates. 

multiplicand multiplicator 



■ <o- 




















































194 


Combinational circuits 


Figure 3.102. The value generated by the AND gates is added 
with full-adders. 



P7 P6 P5 P4 P3 P2 PI P0 


To solve the problem in a nice way, it is necessary to build specific 
cells, using a full-adder. As it can be seen in the following figure, one 
addend receives the product calculated by the AND gate, whereas 
the other addend receives the value from the previous row. 



















Combinational circuits 


195 


Figure 3.103. Cell used to build the matrix that adds and shifts 
the multiplicand. 


Si 


V 


Ai 


V 



Si = sum input 
Ai = A input = multiplicand 
Bi = B input = multiplicator 
Ci = carry in 

So = sum output = ((Ai AND Bi) + Si + Ci) 
Ao = Ai 
Co = carry out 
Bo = Bi 


The cells of the previous figure should be connected properly to¬ 
gether: the following figure shows a solution limited to unsigned 
multiplicand and multiplier. 





196 


Combinational circuits 


Figure 3.104. 4-digit unsigned integer multiplication, producing 
an 8-digit result: P=AxB. 



To multiply signed integers, it is necessary an additional control in¬ 
put, used to specify if the input data is signed, then the net should be 
extended as if the multiplicand and the multiplicator have a double 
bit size, extending their values conforming to the original sign that 
they are intended to have. 
























































































































Combinational circuits 


197 


Figure 3.105. Full solution (but excessively heavy) to calculate 
the product of two 4-bit integers. 



p 






































































































































































































































198 


Combinational circuits 


The sign problem can be resolved changing the sign, before and af¬ 
ter the multiplication, so that a simple unsigned circuit can be used. 
In the following figure, the module MUL4 is a multiplication cir¬ 
cuit that can accept only unsigned values; the modules minus4 and 
minus8 are circuits that can change the sign of the values that they 
filter, if their input minus is asserted. 


Figure 3.106. Signed integer multiplication, using an adapted un¬ 
signed multiplier. 







































Combinational circuits 


199 


The figure above shows that from the inputs A and B the most signif¬ 
icant bit is used to know their signedness; if they are negative, their 
value is converted into positive, before the multiplication. After the 
multiplication, if the input signs were different, the result would be 
converted into a negative value. This sign transformation is enabled 
by the control input Signed , so that unsigned number can be multi¬ 
plied as well. The module minus4 corresponds to the one shown in 
the section 3.14, whereas the minus8 module is an extension work¬ 
ing with 8 bits. 

It should be observed that if the result is truncated to the same num¬ 
ber of digits than the multiplicand and the multiplier, assuming that 
the result can fit in it and that the input data is always signed, then 
the result is valid, without the need to handle the signedness. The 
following examples try to demonstrate this assertion. 


200 


Combinational circuits 


Figure 3.107. 4-digit binary multiplication, truncating the result 
at the same size as multiplicand and multiplier. 


integer 
multiplication 
without sign 

negative 

multiplicand, 

positive 

multiplier 

positive 

multiplicand, 

negative 

multiplier 

negative 

multiplicand, 

negative 

multiplier 

1011 x 

1101 x 

0101 x 

1011 x 

1101 = 

0010 = 

1110 = 

1101 = 

1011 + 

0000 + 

0000 + 

1011 + 

0000 + 

1010 + 

1010 + 

0000 + 

1100 + 

0000 + 

0100 + 

1100 + 

1000 = 

0000 = 

1000 = 

1000 = 

1111 

1010 

0110 

1111 

invalid result 

valid result 

valid result 

valid result 

because it is 




truncated 




too early 













Combinational circuits 


201 


Figure 3.108. Simplified multiplication combinational circuit 
with the result truncated to the same bit size as the multiplicand 
and multiplier. 



P 


<ro 





























































































202 

3.16 Division 


Combinational circuits 


The binary division requires to iterate the subtraction and the bit 
shifting, as the following example shows: the divisor is compared 
with the dividend, starting from the most significant digits, subtract¬ 
ing the divisor from the dividend only if it is possible. That way, the 
integer division result (quotient) is made of Is when the subtraction 
is possible and Os otherwise, whereas the remainder is what remains 
after all the subtractions. 

Figure 3.109. Unsigned integer division procedure. 

13-r5=2, remainder 3 1101^0101=0010 

0001101 

can subtract? 0 10 1 no 

- -0 

0001101 

can subtract? 0 0 10 1 no 


0001101 

can subtract? 0 0 0 1 0 1 yes 

0000011 

can subtract? 0 0 0 0 1 0 1 no 

-- 0 

0 0 0 0 0 1 1 -remainder 

To resolve the division problem with a combinational circuit the full- 
subtractor module can be used, including some more circuitry to 
check if the subtraction can be applied. As for the multiplication, 
a specific module can be designed. 











Combinational circuits 


203 


Figure 3.110. Conditional subtraction cell. 

M 

v 

Si 

v 

SF = full—subtractor 
M = minuend 
Si = input subrahend 

< Bi So = output subtrahend: copy for the next cell 
Bi = Borrow in 
Bo = borrow out 

OKi = OK in: the subtraction can be done, 
OKo = OK out: copy of OKi for the next cell 

- OKo 


D So 

With these cells, after every subtraction it is known if there is a bor¬ 
row from the last Bo output (borrow out) on the left. If there is a 
borrow, then the subtraction can not be done, so the final borrow 
output is used inverted to select the subtracted value or the original 
one (the OKi input). 



OKi > 





204 


Combinational circuits 


Figure 3.111. Solution example for the unsigned integer division. 



When the division is signed, the following cases should be consid¬ 
ered to decide the quotient and the remainder signs: 


Dividend 

Divisor 

Quotient 

Remainder 

+ 

+ 

+ 

+ 

+ 

— 

— 

+ 

— 

+ 

— 

— 

— 

— 

+ 

— 


To solve the signed division problem, a mechanism that changes the 
signs, before and after the division, might be the best way. 











































































































Combinational circuits 


205 


Figure 3.113. Signed integer division: DIV4 can divide only un¬ 
signed numbers; minus4 changes the sign of a value if the input 
Signed is asserted. 


Signed 

>- 


dividend 

A 

V 


0 


[2] 


□ 


□ 


•"[ 1 ] 


/ 


/ I 


divisor 

B 

V 


< [ 1 ] 




i—i 


IN 


IN 

minus 

minus4 

-► 

minus 

minus4 

OUT 


OUT 


2m /Fm 


DIV4 

Q R 


IN 

minus 

minus4 


OUT 

Q 

quotient 


[3] 


IN 

minus 

minus4 


OUT 


M 


[1 ] the more significant bit 
is used to know the sign 
of the value 

[2] dividend and divisor 

signs are different 

[3] the remainder sign 
depends only from 
the dividend 


R 

remainder 













































206 


Combinational circuits 


3.17 Magnitude comparator 


To obtain a magnitude comparison of two unsigned binary integers, 
it is necessary to compare the digits of both values, starting from 
the more significant ones. For every digit comparison it is necessary 
to establish which is the higher or if they are equal. The following 
figure shows the comparison between two simple logic values. 


Figure 3.114. 1-digit magnitude comparator; the diagram on the 
right side is the same circuit with a more compact representation. 


> 


> 


B 


AB 


> 


^ A>B 


> 


EQ 


BA 


^ A = B 


^ B> A 


>C 

> 


When more bits are compared, the match starts from the most signif¬ 
icant bit, which prevails over the others. If the most significant bits 
are the same, the next digit should be checked to find which value is 
greater than the other; if all the digits of the two values are the same, 
the values are equal. 















































Combinational circuits 


207 


Figure 3.115. 4-bit unsigned integer magnitude comparator. 


A = B 

EQ 


A > B 

AB 


B > A 

BA 



BA3 



































































































































208 


Combinational circuits 


Listing 3.116. 4-digit magnitude comparator, Verilog gate level 
implementation. 


module magnitude_ 

.4 (BA, EQ, AB, A, B) ; 

input [3:0] A, 

B; 

output 

BA, 

EQ, 

AB; 

wire [3 

: 0 ] 

ab; 


wire [3 

: 0 ] 

eq; 


wire [3 

: 0 ] 

ba; 


// 




assign 

#3 

ab [0] 

= A[0]& ~B[0 ] ; 

assign 

#3 

ab [1] 

= A[1]& ~B [ 1] ; 

assign 

#3 

ab [2] 

= A[2]& ~B[2]; 

assign 

#3 

ab [3] 

= A[3]& ~B[3]; 

// 




assign 

#3 

ba [0] 

= ~A[0]&B[0]; 

assign 

#3 

ba [1] 

= ~A[1]&B[1]; 

assign 

#3 

ba [2] 

= ~A[2]&B[2]; 

assign 

#3 

ba [3] 

= ~A[3]&B[3]; 

// 




assign 

#3 

eq [0] 

= ~(ab [0] |ba[0]); 

assign 

#3 

eq [ 1 ] 

= ~ (ab[1] Iba[1]); 

assign 

#3 

eq [ 2 ] 

= ~(ab[2] |ba[2]); 

assign 

#3 

eq [3] 

= ~(ab [3] |ba[3]); 

// 




assign 

#4 

EQ = 

eq [ 0]&eq[1]&eq[2]&eq[3 ] ; 

// 




assign 

#3 

AB = 

(ab [0]&eq[1]&eq[2]&eq[3] ) 



1 

(ab [1]&eq[2]&eq[3] ) 



1 

(ab[2]&eq[3]) 




Combinational circuits 


209 


Iab [ 3]; 

// 

assign #3 BA = (ba[0]&eq[1]&eq[2]&eq[3]) 

| (ba [1]&eq[2]&eq[3]) 

| (ba [2]&eq[3]) 

Iba [3]; 

endmodule 


A common 4-bit magnitude comparator circuit is the 7485 (see 
il .4.2). 



210 


Combinational circuits 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


211 


Chapter 


Arithmetic-logic unit 

4.1 Status flags . 212 

4.2 Size truncation . 216 

4.3 Sign inversion . 219 

4.4 Addition and subtraction . 221 

4.5 Shift and rotation . 223 

4.6 Magnitude comparison . 229 

4.7 Multiplication . 233 

4.8 Division . 239 

4.9 Logic unit. 244 

4.10 Joining all the modules together . 246 

4.11 Bit sliced ALU . 248 


addition 221 ALU 246 248 bit-size 216 bit slice 248 carry 212 
comparison 229 division 239 flag 212 multiplication 233 negative 
212 overflow 212 221 223 rank 212 216 rotation 223 shift 223 sign 
212 219 size 216 status 212 subtraction 221 zero 212 


The arithmetic-logic unit (ALU) is a combinational circuit that con¬ 
tains the main calculation functions of a CPU. It is usually composed 
by some distinguished circuits, everyone of which does a single or 
a little group of calculations. These components are usually joined 
together through a multiplexer that selects the chosen result. 













212 


Arithmetic-logic unit 


Figure 4.1. Simplified diagram of three components working to¬ 
gether in a single ALU: everyone receives a couple of input val¬ 
ues, but the output is selected by a multiplexer, through a control 
code that represents the function requested to the ALU. 


function 2 

> -^-1 

00=addition (A plus B) 

01 =multiplication (Ax B) 
10=division remainder (A % B) 
11-division quotient (A /B) 



B 

v 


32 


/ 


/ 


32 






/ / 32 


/ / 32 


V 

result 


Where possible, the examples of the chapter are divided into 8-bit 
modules, which might be connected together to work with multiple- 
bit sizes: 16, 32, 64. 


Common circuit components used to build an ALU are: 7483, 7485, 
74181, 74182, 74381 and 74382 (see u0.4). 


4.1 Status flags 

For some kind of operation the ALU needs to remember a previous 
status; for example, an addition might be done in more than one step, 
taking into account the previous carry. Some flags are used to keep 







































Arithmetic-logic unit 213 

track of the status of previous operations; the most common ones 
are: carry , zero , sign and overflow. 


Name 

Common 

abbreviation 

Description 

zero 

z 

Asserted when the last operation result 
was zero. 

negative sign 

N 

Asserted when the last operation result 
seems to be negative, because the most 
significant bit is 1. 

carry 

C 

Usually asserted when the last opera¬ 
tion requires an additional digit to store 
the value and the effective result is trun¬ 
cated, but used also for other situations 
when a digit should be saved for iterated 
calculations. 

overflow 

0 

V 

The overflow is a condition that arise 
when the result of an operation is not 
valid because it is truncated at the most 
significant side or because it has the 
wrong sign. When adding two integer 
values there is an overflow if the last two 
carries are different. 


To verify a result equal to zero it is possible to check the output value 
with a NOR gate, which produces a 1 only if all the inputs are 0. It 
is also easy to find the sign of a value (assuming that the value is 
signed) checking the most significant bit. 




214 


Arithmetic-logic unit 


Figure 4.3. Module zn8 : check for zero and for a possible sign. 
On the right side the same circuit appears with a compact dia¬ 
gram, where the eight input lines are grouped together in a single 
multiline port. 


D7 D6 D5 D4 D3 D2 D1 DO 



If it is required to operate with different bit-sized data, the above 
module can be used in parallel, adding a rank selection, like the 
following figure shows. 









































Arithmetic-logic unit 


215 


Figure 4.4. Module zn32 : zero and sign evaluation for integers 
from 8 to 32 bits. The input port rk , which stands for ‘rank’, is 
a control function allowing to specify the desired bit-size: zero 
means 8 bits, up to 3 that means 32 bits. The module zn8 is 
described in figure 4.3. 


y data 





216 

4.2 Size truncation 


Arithmetic-logic unit 


The modules described in the following sections allow to operate 
on 32-bit values and on smaller sizes (multiples of 8). When the 
specified size is smaller than 32 bits, the results are valid only inside 
that particular rank and there might be also more contents that should 
be ignored on the more significant side, beyond the specified range. 
The following module allows to filter a value and even to extend the 
sign, based on a selected size. 








218 


Arithmetic-logic unit 


Figure 4.6. Module rk, identical to the previous picture, but de¬ 
signed in a more compact way. 


v in 


/ 2,2 



























































































Arithmetic-logic unit 


219 


4.3 Sign inversion 

To assist the multiplication and the division it is important a mod¬ 
ule that can invert the sign of a (signed) binary integer number. The 
module minus8 works on 8 bits and it is used to build other inversion 
modules with a bigger bit-size. 


220 


Arithmetic-logic unit 


Figure 4.7. Module minus8 : 8-bit sign inversion. If the inputs M 
and Ci are asserted the sign is inverted, otherwise the value is not 
changed. The module ha is a common half-adder. 




























































































Arithmetic-logic unit 


221 


Figure 4.8. Module minus32 : 32-bit sign inversion, made of four 
minus8 modules, as described in figure 4.7. 


i 

V M 



O 

4.4 Addition and subtraction 

The following figure shows an 8-bit module that is able to add and 
subtract integer values, handling correctly either the carry or the bor¬ 
row, signaling also the overflow (if the last two carries are different). 












































222 


Arithmetic-logic unit 


Figure 4.9. Module as8: addition and subtraction of 8-bit binary 
integers. The input / (function) selects the addition or the sub¬ 
traction; the output O gives the overflow (if there is one). The 
module fa is a full-adder. 


f-0: S = A+B+Ci, Co contains the final carry if there is one 
carry in f-1: S - A—B—Bi , Bo contains the final borrow , if there is one 


borrow in 



Co 









































































































Arithmetic-logic unit 


223 


Figure 4.10. Module as32 : addition and subtraction with the pos¬ 
sibility to control the bit size. The module as8 is described in 
figure 4.9. 

rk A B f Ci 


V V V V V 



Co O S 


4.5 Shift and rotation 

The following figure shows a module that is able to do a logical 
and arithmetical shift on 8 bits. The ports lin , lout , rin and rout 
(left/right in/out) are there to allow shift and rotation on multiples 
of 8 bits. The output ports Cl and Cr (carry left/right) contain al¬ 
ways the bit value that is shifted outside (on the left or on the right 




























































































224 


Arithmetic-logic unit 


side), whereas the output port O (overflow) is asserted only when an 
overflow is produced, due to an arithmetic left shift that changes the 
sign. 



Arithmetic-logic unit 


225 


Figure 4.11. Module sh8: 8-bit logic and arithmetic shift. 


rout 

right out A 


nn 

v right in 


A>— ^ 


0=logic shift 
1 =arithmetic shift 

la > 

lr 


right 

side 

carry 


[1] Arithmetic shift: 

- the shift should be arithmetic; 

- it should be a right shift; 

- the most significant bit should be L 

[2] Overflow: 

- the shift should be arithmetic; 

- the most significant bit should not 
have changed . 

[3] Connection to the most significant 
digit or to the sign . 

[4] Connection to the least significant digit 
[Cl] Left carry: 

- it should be a left shift; 

- the original most significant digit is L 
[Cr] Right carry: 

- it should be a right shift; 

- the original least significant digit is L 



left 

side 

carry 


left out 


lout 
















































































































O=logic shift 
l=arithmetic shift 


226 


Arithmetic-logic unit 


Figure 4.12. Module sh32 : from 8 to 32-bit logic and arithmetic 
shift. The C output (carry) returns the bit value that is shifted 
outside either on the left or the right side. The module sh8 is 
described inside the figure 4.11. 



S 





















































































Arithmetic-logic unit 


LI 


Figure 4.13. Module ro32 : from 8 to 32-bit rotation. As there is 
no ‘arithmetic’ rotation, there is no overflow either. The module 
sh8 is described in figure 4.11. 













228 


Arithmetic-logic unit 


Figure 4.14. Module rc32 : rotation with carry (the input carry is 
inserted from one side and the output carry, at the opposite side, 
is saved for the next rotation). The module sh8 is described in 
figure 4.11. 


Ci 


A 


lr 


rk 



S 


Co 























































































Arithmetic-logic unit 


229 


4.6 Magnitude comparison 

The module cmp8 compares the magnitude of two unsigned values, 
asserting a different output port depending on the three possible con¬ 
ditions: A>B , A<B, A=B. 


230 


Arithmetic-logic unit 


Figure 4.15. Module cmp8 : 8-bit integer unsigned magnitude 
comparison. 

A B 



The module cmp8 can be used to compare two values with a multiple 
bit size; in that case it is possible to introduce extra logic to consider 
even the sign: if the input values to be compared are signed and if the 
signs are different, the result should be reversed. The module cmp32 










Arithmetic-logic unit 231 

compares two 32-bit values, returning a 32-bit value: 0 if the values 
are equal, +1 if A>B\ -1 if A<B. 



232 


Arithmetic-logic unit 


Figure 4.16. Module cmp32 : signed or unsigned 32-bit magni¬ 
tude comparison. The module cmp8 is described in figure 4.15. 







Arithmetic-logic unit 


233 


The module cmp32 does not allow to reduce the bit range to be 
compared; therefore, if there is the need to control the input bit size, 
it is necessary to add the module rk as a filter (figure 4.5). 


Figure 4.17. Input filter with the module rk (figure 4.5). 

A B 

V V 



M 

4.7 Multiplication 

As already described in a previous chapter, the multiplication re¬ 
quires a special module that adds the result of the AND operation 
between the two input values. This module is resumed inside the 
following figure. 



























234 


Arithmetic-logic unit 


Figure 4.18. Module mul : 1-bit multiplication. This module is 
used inside the one that multiplies 8-bit values. 


si ai 

V V 



si = sum input 
ai = a input = moltiplicand 
bi = b input = moltiplicator 
ci = carry in 

so = sum output = ((ai AND bi) + si + ci) 
ao = ai 
co = carry out 
bo = bi 


so 

The following figure shows the module mul8 , which is a 8-bit mul¬ 
tiplier with all the required ports to connect with other similar mod¬ 
ules. 































































236 


Arithmetic-logic unit 

As the module mul8 is complex even if used alone, the following 
figure shows how to use it to multiply 8-bit values. 

Figure 4.20. How to use the mul8 module alone. 



To proceed gradually, the following figure shows a module that mul¬ 
tiply 16-bit values, using four mul8 modules. 









Arithmetic-logic unit 


Figure 4.21. Module mull6 : 16-bit modules. The module mul8 
is described in figure 4.19. 


A 

V 



D0> 







Arithmetic-logic unit 


5 


Figure 4.22. Module mul32 : 32-bit signed and unsigned multi¬ 
plication. The module mul8 is described in figure 4.19, whereas 
the modules minus are described starting from the figure 4.7. 
















Arithmetic-logic unit 

4.8 Division 


239 


« 


As already described in a previous chapter, the division requires a 
special module to subtracts the divisor from the dividend. This mod¬ 
ule is resumed inside the following figure. 


Figure 4.23. Module div: 1-bit division. This module uses an fs 
module, which is a full-subtractor (see section 3.10). 


m 

v 


si 

v 


bo « 


oki > 



<bi 


oko 


fs = full subtractor 

m = minuend 

si = input subtrahend 

so = output subtrahend 

bi = input borrow 

bo = output borrow 

oki = input ok: the subtraction is valid 

oko = output ok: the subtraction is valid 


Y 

d 


Y 

so 


























Arithmetic-logic unit 


J 

Figure 4.24. Module div8 : 8-bit integer unsigned division. There 
are 64 div modules, used to subtract the divisor from the divi¬ 
dend, until the quotient and the remainder are found. The module 
div is described in figure 4.23. 


























Arithmetic-logic unit 


241 


Figure 4.25. Usage example for the module div8 alone. The mod¬ 
ule div8 is described in figure 4.24. 


divisor dividend 



remainder 







242 


Arithmetic-logic unit 


Figure 4.26. Module divl6 : 16-bit integer unsigned division. 
Four modules div8 are used. The module div8 is described in¬ 
side the figure 4.24. 

B A 

V V 


divisor 


dividend 



R 







Arithmetic-logic unit 


243 


Figure 4.27. Module div32 : 32-bit signed integer division. There 
are sixteen div8 modules and four minus32 modules to control 
the sign if the input data is meant to be signed. The module div8 
is described in figure 4.24, whereas the module minus32 can be 
found in figure 4.8. 






















244 


Arithmetic-logic unit 


4.9 Logic unit 

A logic unit is a module that calculates bitwise boolean operations. 
The common operations available are usually NOT, AND, OR and 
XOR, but the example in the following figure shows all the cases of 
the table 3.6, even if many of them are unnecessary. 


Arithmetic-logic unit 


245 


Figure 4.28. Module logic32 \ all the sixteen logic operations that 
can be defined in a combinational circuit with two input ports 
and a single output. In this case, every logic gate is multiplied 32 
times in parallel. 


fi 

00 

1 NOR 

2 AB 

3 A 
4A-B 
5 B 
6XOR 
7NAND 
8 AND 
9NXOR 
10 B 
11A+B 
12 A 
13A+B 

14 OR 

15 1 

f>- 


A 

V 



V 

L 


PQ> 






























































































246 


Arithmetic-logic unit 


4.10 Joining all the modules together 

In the following figure there is an ALU with all the modules de¬ 
scribed in the previous sections. Please notice that the proposed so¬ 
lution is not optimal and it has only a demonstration purpose. 


Arithmetic-logic unit 


247 


Figure 4.29. Module alu32 : 32-bit ALU. The input F represent 
the requested function that the ALU should execute. 





























































































































































248 

4.11 Bit sliced ALU 


Arithmetic-logic unit 


If the requested functions are limited and the addition can be ob¬ 
tained with the simple ripple-carry method, it is possible to design a 
bit-sliced ALU that is a single bit ALU, which can be expanded to 
any bit-size. 

Figure 4.30. Module as: f =0 requires the addition with carry; 

/= 1 requires the subtraction with borrow; if the output carry is 
different from the input one, there is an overflow. 


f A B 

V V V 

































































250 


Arithmetic-logic unit 


Figure 4.32. Module Itgt : magnitude comparison. The compari¬ 
son is made at the bit level, using the input carry if the values are 
the same. The result is transferred to the next module through the 
output carry. The module is made of two parts: It (A<B) and gt 
(A>B). The overall module does the first and the second com¬ 
parison, based on the function/. The equality match is not done, 
because it can be obtained with the NXOR operator. 









252 


Arithmetic-logic unit 


Figure 4.33. Module shl: left shift. The shift uses the ‘normal’ 
carry. The shift does not consider the sign; the input / is used to 
select the operand to shift: either A or B . 


f A B 

V V V 

_Xo i 



o 


SHL 



Arithmetic-logic unit 


253 


Figure 4.34. Module shr : right shift. The shift is done using a 
reversed carry line where the names Di and Do are used. The 
shift does not consider the sign; the input / is used to select the 
operand to shift: either A or B. 

f A B 


V V V 



SHR 



254 


Arithmetic-logic unit 


Figure 4.35. Module z: zero. It verifies if the value is zero and 
if all the previous ones are reporting the same (through the carry 
line). The input/ allows to select which operand to check. 


f A B 

V V V 





Arithmetic-logic unit 


255 


Figure 4.36. Module alu : 1-bit ALU, made of the previous mod¬ 
ules. 




































































































256 


Arithmetic-logic unit 


Figure 4.37. 4-bit ALU using four alu modules. 



TKGate 2 does not work correctly when a gate bit-vector input port 
is negated; so, the gates 2, 4, 11 and 13 would not work with it. 

































































































“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


257 


Chapter 


Latch and flip-flop 

5.1 Propagation delay . 258 

5.2 Truth tables . 260 

5.3 SR latch . 261 

5.4 Bounce-free switch . 269 

5.5 Gated SR latches. 271 

5.6 SR flip-flop . 275 

5.7 Time: setup/hold and recovery/removal . 279 

5.8 D latch and D flip-flop . 280 

5.9 T flip-flop . 286 

5.10 JK flip-flop . 288 

5.11 Troublesome JK flip-flops . 291 


bounce free 269 delay 258 D flip-flop 280 Earle latch 280 
edge-triggered 275 flip-flop 257 275 gated D latch 280 hold time 
279 JK flip-flop 288 291 latch 257 master-slave 280 memory 257 
propagation delay 258 recovery time 279 removal time 279 
sequential circuit 257 setup time 279 SR flip-flop 275 SR latch 261 
switch 269 transparent latch 280 T flip-flop 286 


The combinational circuits transform the input data into the output 
data, according to a certain function, without taking into account 
any previous status: the data is translated always in the same way, 













258 


Latch and flip-flop 


after a little amount of time. Because of this characteristic, the com¬ 
binational circuits are said to be memoryless. Instead, a sequential 
circuit takes into account the dynamic on which the input data is re¬ 
ceived, keeping a status , which is updated by the circuit itself and 
which is in fact an additional source of input data that influences the 
output result. 

The sequential circuits are based on components known as memo¬ 
ries, which are made of latches or flip-flops. A latch is a circuit with 
some kind of feedback, by which one or more output lines become 
input again; a flip-flop is a sophisticated latch which is responsive to 
the variation of a data. 

5.1 Propagation delay 

Every combinational circuit reacts to the input data variation updat¬ 
ing the output with a little time delay, known as the propagation 
delay. The amount of the delay time depends on the physical and 
mechanical characteristics of the real circuit. 


Latch and flip-flop 


259 


Figure 5.1. An impulse signal traversing a buffer shows on the 
output a little delay. 

a 



oscillator 





a 




q 



< > 

propagation delay 


The propagation delay might be used to produce a short impulse, as 
the following figure shows. 


Figure 5.2. A short impulse produced by the delay propagation. 



oscillator 










260 


delay introduced by the inverter 


Latch and flip-flop 


a_| i |_| |_ 

b- H II I -1_|- 

q_U-11_n_ 

delay introduced by the AND gate 

5.2 Truth tables 

The truth table is a way to explain the combinational circuit be¬ 
haviour, where the output values are shown as functions of the in¬ 
put ones, without considering either the propagation delay or the 
dynamic that the input data might have. To explain a sequential cir¬ 
cuit behaviour a kind of truth table might be used, but in that case 
the notations should be understood depending on the particular con¬ 
text. The following sections introduce latches and flip-flops, which 
might be influenced by the input data signal variations, therefore the 
following notation is used: 

0 stable 0 

_/“ variation from 0 to 1, or positive edge 
1 stable 1 

“\_ variation from 1 to zero, or negative edge 








































Latch and flip-flop 


261 


0 J - 1 

5.3 SR latch 




0 


The simplest sequential circuit that keeps its status memory is the 
one shown in the following two figures, made either with NOR or 
NAND gates. With the NOR gates example, the Q output is ini¬ 
tially unknown and might be either 0 or 1; then, asserting the S in¬ 
put (set) even with a short positive impulse, the Q output is asserted 
(activated) and it remains active until the R input (reset) remains 
negated. That is: a short positive impulse to the S input sets the out¬ 
put, whereas the same impulse to the R input resets the output. With 
the example based on NAND gates, the inputs S and R are negated, 
so that the set and reset impulse should be negative. 









262 


Latch and flip-flop 


Figure 5.5. Simple set-reset latch with NOR gates. 


R> 

S> 


reset 



Or 


Q 


s 

R 

Q 

0 

0 

unchanged 

0 

_/- 

0 

0 

1 

0 

0 


0 

_/■ 

0 

1 

_/■ 

_/- 

0 


1 

0 

_/■ 


1 

1 

0 

1 

1 

_/- 

0 

1 

1 

0 

1 

■\_ 

1 

-\_ 

0 

1 


_/■ 

0 


1 

0 



not allowed! 
























Latch and flip-flop 


263 


Figure 5.6. Simple set-reset circuit with NAND gates. 



Q 


s 

R 

Q 

0 

0 

1 

0 

_/■ 

1 

0 

1 

1 

0 

-\_ 

1 

_/- 

0 

0 

_/■ 

_/- 

non allowed! 


1 

1 

_/- 


0 

1 

0 

0 

1 

_/- 

0 

1 

1 

unchanged 

1 


0 

-\_ 

0 

1 


_/- 

1 


1 

1 



1 


The two figures above show a circuit and the corresponding truth 
table, which highlights a condition that is not allowed: the NOR cir¬ 
cuit should not let both inputs change from 1 to 0 simultaneously, 
whereas the NAND one should not let both input change from 0 to 
1 simultaneously. The reason for the not allowed condition is ex¬ 
plained later. 

The above figures represent a simplified version of a kind of circuit 




















264 


Latch and flip-flop 


known as SR latch , which usually has another negated output, Q , 
which gets the opposite value of Q. 


Figure 5.7. SR latch with NOR gates. 


R >-\ 

>1 



/ 

¥ 





> Q 

s> 

\ 

1 ^ 

- i 


S Q 
R Q 


s 

R 

Q 

O 1 

0 

0 

unchanged 

0 

_/- 

0 

1 

0 

1 

0 

1 

0 


0 

1 

_/■ 

0 

1 

0 



0 

1 


1 

0 

1 


-\_ 

1 

0 

1 

0 

1 

0 

1 


0 

1 

1 

1 

0 

0 

1 

-\_ 

1 

0 

-\_ 

0 

1 

0 


_/■ 

0 

1 


1 

0 

1 



not allowed! 



























Latch and flip-flop 


265 


Figure 5.8. SR latch made with NAND gates. 


s > 


o- 


Q 


R > 



^ Q 


s 

R 

Q 

Q 

0 

0 

1 

1 

0 

_/■ 

1 

0 

0 

1 

1 

0 

0 


1 

0 

_/- 

0 

0 

1 


_/■ 

not allowed! 


1 

1 

0 

_/- 


0 

1 

1 

0 

0 

1 

1 

_/- 

0 

1 

1 

1 

unchanged 

1 


0 

1 

-\_ 

0 

1 

0 


_/- 

1 

0 


1 

1 

0 



1 

0 
























266 


Latch and flip-flop 


Figure 5.9. SR latch with NAND gates, changing the meaning of 
the input lines. 


R > 





S> 



> Q 


s 

R 

Q 

Q 

0 

0 

1 

1 

0 

_/- 

0 

1 

0 

1 

0 

1 

0 


0 

1 


0 

1 

0 


_/■ 

not allowed! 


1 

0 

1 


-\_ 

1 

0 

1 

0 

1 

0 

1 

_/■ 

1 

0 

1 

1 

unchanged 

1 

-\_ 

1 

0 

-\_ 

0 

1 

0 


_/■ 

0 

1 


1 

0 

1 



1 

0 






The SR latch made with NAND gates is equivalent to the NOR one 
























Latch and flip-flop 


267 


with the input ports negated; however, the SR latch with NAND 
gates is also used changing the input port names as it is shown in 
the last figure above, but this way the behaviour is no more equal to 
the NOR gate version, although it is nearly the same. For that reason, 
when an SR latch is drawn as a box, it is necessary to specify which 
truth table is used; anyway, the SR latch alone is used very seldom 
and it is advisable to depict it with logic gates and not only as a box. 

Figure 5.10. NOR SR latch traces showing two critical situa¬ 
tions: the first time both the input ports are asserted and becomes 
negated simultaneously; the second time the inputs impulse is 
too short. 



S_ 

RJ 

Q 

Q — 




ri r 

~i r - 


\ * 

i mnnnn 

JUWUL 

tr 


mnnnn 


reset 

set 


resonance 


T 

set and reset to zero at the same time 





















































































Latch and flip-flop 


268 


S 

R 

Q 

Q 




JL 


irxFimnr 

JUtMJUULTL 


ixnnnnnnnnnnii 


njuuuuuuuu^^ 

resonance 


J1 


too short pulses 


The above figure shows a NOR SR latch timing diagram, where the 
propagation delay is evidenced, but especially is visible what hap¬ 
pens when the input ports drop to zero simultaneously: because of 
the propagation delay, the two outputs remains for a while to zero, 
but then, as the inputs are now zero, the outputs are activated and 
that starts a loop of deactivation and activation. This is the problem 
that imposes to avoid to drop to zero the input ports simultaneously. 
But even a too short pulse might create troubles: the input impulse 
should be long enough to allow the latch to change its state (if that 
impulse should change it). 

The SR latch is the basis for all other latches and flip-flops; that 
is why it is important to know in how many ways it can be imple¬ 
mented, as the following figure shows. 







































Latch and flip-flop 


269 


Figure 5.11. SR latch in many equivalent implementations, 
where care should be given to the input ports order. On the left 
side there are the active-high input versions, whereas on the right 
side appear the ones with active-low inputs. The most common 
SR latches are highlighted: NOR and NAND. 


R 

f r>t 

u 

R 

pT>t 

Q 

S 




S 





J-Q 

—<£>- 

Q 














« 


270 

5.4 Bounce-free switch 


Latch and flip-flop 


When building real electronic logic circuits, switches are often used, 
but in the real world, these components have the ‘bounce’ problem, 
which means that opening or closing the switch some unwanted im¬ 
pulses are generated. To avoid these impulses the SR latches are 
used, for example in the way shown by the figure below. 

Figure 5.12. SR latch used to filter the bounces produced by a 
switch. 





Q 


Q 



























































Latch and flip-flop 

5.5 Gated SR latches 


271 


The SR latch can be extended including two control gates to en¬ 
able the set-reset input lines. In practice the new SR latch has an 
additional input port used to enable the other two inputs: when the 
enable input is asserted, the SR latch works as usual, but when it is 
negated, the other input lines are just ignored. 


Figure 5.13. Gated SR latch: when the E input (enable) is as¬ 
serted, it works as the usual SR latch; when the E input is 
negated, the other inputs are ignored. The circuit appears in the 
two common versions, together with the usual symbology. 


R 

E 

S 

S 

E 

R 



Q 

Q 

Q 

Q 


S Q 

E 

R Q 


The two diagrams in the above figure are equivalent and it can be 
demonstrated with the De Morgan’s laws. 








































































Latch and flip-flop 


Figure 5.14. Gated SR latches equivalences. 


(a + b) = a • b 








Latch and flip-flop 


273 


lem already described: the enable input should be asserted only when 
the other inputs are in a valid condition, avoiding the case when both 
S and R are asserted at the same time, because when the enable input 
becomes negated, it would trigger the resonance. 


Figure 5.15. Truth table for a gated SR latch, limited to the most 
significant cases. 




Q 



s 



Q 




Q 


E S R 

Q Q 

O XX 

unchanged 

0 0 

unchanged 

0 1 

0 1 

/■■\ 1 0 

1 0 

1 1 

not allowed! 

1 '\_ '\_ 

not allowed! 

-\_ 1 1 

not allowed! 


When a gated SR latch is turned on, the initial output status is unde¬ 
termined. To be able to initialize the circuit it is necessary to extend 
the input ports of the internal SR latch, as the following figure shows. 
It should be noticed that, depending on the internal SR latch imple¬ 
mentation, the initialization signal might be asserted high or low. 

































































274 


Latch and flip-flop 


Figure 5.16. Gated SR latch with initialization inputs: when the P 
or P input is asserted (preset), the Q output activation is forced; 
when the C or C input is asserted (clear), the Q output activation 
is forced, clearing the other output port. 



p- 

preset 



Latch and flip-flop 


275 


P 

s 

E 

R 

C 


preset 



clear 


5.6 SR flip-flop 

The gated SR latch has an enable input that, when asserted, allows to 
receive set and reset assertion from the other inputs, but if the enable 
input is to be used as a way to update the latch in a precise moment, 
the enable signal must be short enough to avoid that any change can 
happen in the meantime. To resolve properly the problem, two gated 
SR latches can be connected, one after the other as ‘master’ and 
‘slave’, inverting the enable input to the second one: this way the 
output of the whole circuit is updated when the enable signal passes 
from high to low, that is the negative edge : this kind of latch is a 
flip-flop and it might be triggered with a negative or a positive edge, 
depending on the implementation. 













































276 


Latch and flip-flop 


Figure 5.17. Positive and negative edges of a signal, 
positive edge negative edge 


Figure 5.18. Negative edge triggered SR flip-flop: when the en¬ 
able signal goes from 1 to 0, the flip-flop is updated. The circuit 
is shown starting from the block diagram and then with the com¬ 
mon gate implementations. It should be noticed that the enable 
input is now called ‘clock’ and it is usually shown as a triangle. 












-► 

s 

Q 

-► 


S 

Q 



S 

Q 


-► 

E 

D 



-► 

E 




> 



-► 

K 

Q 

-► 


R 

Q 


■> 

R 

Q 

-► 


negative edge triggered 
SR flip-flop 

























































































Latch and flip-flop 


277 



S 

R 

Clk 

Q 


Q 














































































































































278 


Latch and flip-flop 


Figure 5.19. Negative edge triggered SR flip-flop, with initializa¬ 
tion inputs. 








Latch and flip-flop 


279 



Please notice that the SR flip-flop (positive or negative edge) is never 
used; however, the gated latches connected as master and slave might 
be used to build more specific flip-flops. Furthermore, instead of a 
hypothetical SR flip-flop, the JK flip-flop is used (see section 5.10). 

5.7 Time: setup/hold and recovery/removal 

There are two significant time intervals related to the synchronous 
components, which are the circuits that have a data input controlled 
by an enable or clock input line. These time intervals are the setup 
time , known with the label t su , and the hold time , known with the 
label t h . 

































































280 


Latch and flip-flop 


Figure 5.20. Example of correct and wrong conditions, concern¬ 
ing the setup time (/ su ) and the hold time (4) constraints. 


data | 




A 

A 



AA 













A 

T 

th 

— 

enable/clock 









th 


th 


i 


th 


%u 


%u 




Isu 

; %u 


In different context, when it should be emphasized that the input data 
is asynchronous, other names are used: recovery time and removal 
time. 



recovery 

time 



recovery 

time 



reset 







clock 













removal removal 

time time 


5.8 D latch and D flip-flop 

A gated SR latch or an edge triggered SR flip-flop can be connected 
so that the R input is equal to the inverted S. This way the single 
input line can be called D , for ‘data’, and the new circuit becomes a 
D latch or a D flip-flop. 





















































































Latch and flip-flop 


281 


Figure 5.22. D latch and D flip-flop obtained from a gated SR 
latch or an edge triggered SR flip-flop. 



As for the gated SR latch and the SR flip-flop, the same consideration 
about the setup and hold time apply to the ‘D’ variation. But the D 
latch do not have invalid combination for the input data that comes 
from a single line. 

Figure 5.23. D latch made with NAND gates. When the E input 
is asserted, the circuit receives the data from the D input and it 
reproduces the same value trough the Q output (inverting that 
value at the Q output). 


data 




D 

Q 

E 

Q 












282 


Latch and flip-flop 


Q 

Q 



The D latch can be implemented in more efficient ways, known as 
transparent latch and Earle latch , which appear in the following 
figure. Please notice that the Earle latch has two complementary en¬ 
able inputs, E and E, which should be asserted and negated at the 
same time, to do their work properly. 

Figure 5.24. Transparent latch. 

D >- 


E > 


10 


Q 












r 


^ Q 

























































































Latch and flip-flop 


283 


Figure 5.25. Earle latch. 



The D flip-flop (edge triggered) can be implemented as master-slave, 
but there exists an alternative and more efficient circuit that triggers 
at the positive edge. 

Figure 5.26. Master-slave D flip-flop and classical positive-edge- 
triggered D flip-flop. The timing diagram is related to the second 
version that triggers with positive clock edges. 











ZS4 


negative edge 

D Q 

D flip—flop Q 

> Q 



Clk I l 


wl |_ 

w2 — 

w3 r 

w4 n 

Q 

Q _ 


Latch and flip-flop 


positive edge 
D flip—flop 


D Q 

> Q 

V._> 


>r 


^ Q 


^ Q 


classical positive edge D flip-flop 





















286 


Latch and flip-flop 


preset 



5.9 T flip-flop 

Extending a positive edge D flip-flop it is possible to obtain a T flip- 
flop, where the ‘T stands for ‘toggle’. When the T flip-flop receives 
the clock edge and the T input is asserted, it inverts the output values. 
The truth table uses the notation Q {{) to indicate the Q output value 
at the time t and the notation g (t+ 1 > to indicate the Q output value at 
the next clock effective edge. 









































































Latch and flip-flop 


287 


Figure 5.28. Positive edge T flip-flop: timing diagram and truth 
table. 


t r 

Clk [ 
Q _ 
Q _ 



Y 

when a positive edge clock signal 
is received and the T input is active, 
the output values are inverted 






L 


T 

Q (t+i) 

0 

%) 

1 

Q( t ) 


The T flip-flop requires the clear or the preset input ports, because it 
is necessary to establish an initial value for the outputs. The follow¬ 
ing figure shows how to extend a D flip-flop with clear and preset 
inputs. 































































288 


Latch and flip-flop 


Figure 5.29. AT flip-flop starting from a D flip-flop, which in¬ 
cludes clear and preset inputs. 


Preset > 



> 


T> 


■l 


Clk> 


> 


Clear > 






Preset 

D 


Q 

> 

Q 

Clear 



+ 


Q 


Q 


5.10 JK flip-flop 


Another D flip-flop variation, recalling the SR latch, is the JK flip- 
flop. As for the T flip-flop, the truth table uses notations Q( X) and 
Q( t +i), to specify the Q value at the time t or at the next effective 
clock edge. In short, the JK flip-flop works like the SR latch, where 
J means ‘set’ and K means ‘reset’, but when both J and K inputs 
are asserted, the output values are just reversed, like it happens with 
the T flip-flop. 










































Latch and flip-flop 


289 


Figure 5.30. Positive edge JK flip-flop and truth table. 




J 

K 


J 

0 

0 

0 

Q (o 

unchanged 

> 


0 

1 

0 

reset 

K 

Q 

1 

0 

i 


— 


set 



1 

1 

Q(o 

output inversion 


j 

K 

Clk 


"Li —l 


Q 

i n n 

l 

1 


J,K=0,0| 

J,K=1,0| 


J,K=0,1 

J,K=1,1! 


~L_r 

J,K=0,0 
J,K=1,1 


J,K=0,1 


1 


n 


J,K=1,0 


The JK flip-flop might require the clear or the preset input ports, 
but it is not strictly necessary as for the T flip-flop. Anyway, the 
following figure shows how to extend a D flip-flop with clear and 
preset inputs. 




























































































290 


Latch and flip-flop 


Figure 5.31. JK flip-flop made as an extended D flip-flop with 
clear and preset inputs. 



Clear >- 1 

It should be noticed that the T flip-flop is just a JK one with the 
inputs J and K connected together. 





Latch and flip-flop 


291 


Figure 5.32. JK flip-flop adapted to work as a T one. 



Electronic flip-flops (D, JK, T) are currently produced with a specific 
technology that is not easily translated into common logic gates. The 
JK flip-flop obtained extending the D flip-flop works correctly, but 
there are other circuits inside the traditional documentation and data 
sheets that if reproduced with a simulator would not work as ex¬ 
pected. 

The following figure shows the circuit that can be found inside some 
original 7476 IC data sheets. This kind of circuit should be positive- 
edge triggered by the clock signal, but the timing diagram shows 
that it does not react this way and after the negative edge the circuit 
becomes unstable. 

















292 


Latch and flip-flop 


Figure 5.33. JK flip-flop circuit that does not work. 



A 

Ck 


C i_| 

P J 

ck i_FLJ1 

j i_ 


K i_ 

Q a_ 

q u mwmvmvmwwwwwm™ 


cleared 

should be positive 
edge triggered, 
but it does not change 


at the negative edge the flip-flop becomes unstable 


The following figure shows a master-slave JK flip-flop (negative- 


















































































Latch and flip-flop 


293 


edge triggered) that is described in the traditional documentation. 
This circuit might work, but it does not completely react as expected: 
if the J ox K input signals are negated before the clock negative 
edge, when the clock negative edge actually comes they switch the 
flip-flop anyway. 

Figure 5.34. Master-slave JK flip-flop. 


P > 

J> 
Ck > 
K> 

C > 



> Q 

^ Q 








































































294 


Latch and flip-flop 


C L 
P L 
Ck L 
J L 
K L 
Q _ 
Q _ 


cleared negative 

K goes 


edge 

down 

the output is updated 

output updated 

before 

anyway 

the clock 
negative edge 














































































“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


295 


Chapter 


Registers 

6.1 Multiplexer . 300 

6.2 Simple data register . 301 

6.3 Shift register . 308 

6.4 Asynchronous counter with T flip-flop . 311 

6.5 Synchronous T flip-flop counters . 312 

6.6 Synchronous counters with D flip-flops . 314 

6.7 Synchronous counters with parallel load. 320 


counter 312 314 counter register 311 data register 301 multiplexer 
300 register 295 shift register 308 


A register is a flip-flop array (D flip-flops are used commonly) by 
which it is possible to store binary values or to build a counter. It 
could be possible to build registers with gated latches, but the edge- 
triggered flip-flops are more reliable for the purpose. 

The following examples use D flip-flops following the classical im¬ 
plementation or derived from that kind of circuit. Therefore, these 
are positive-edge triggered flip-flops. 









296 


Registers 


Figure 6.1. Classical D flip-flop. 

preset 



Listing 6.2. Module D1 : Verilog gate level implementation for 
the classical D flip-flop. 

module D1 (Q, _Q, D, Ck, _P, _C); 
output Q, _Q; 
input D, Ck, _P, _C; 
wire wl, w2, w3, w4; 

// 





























































































Registers 


297 


assign 

#6 

wl = 

~ (w3 

& Ck & _C) ; // gl 

assign 

#6 

w2 = 

~ (wl 

& Ck & w4); // g2 

assign 

#6 

w3 = 

~ (_P 

& w4 & wl); // g3 

assign 

#6 

w4 = 

~ (w2 

& D & _C) ; // g4 

assign 

#6 

Q = 

~ (_P 

& wl & _Q) ; // g5 

assign 

endmodule 

#6 

_Q = 

~ (Q & 

w2 & _C) ; // g6 


Figure 6.3. Classical D flip-flop in parallel. 


preset 



C >-* 


clear 

























































































298 


Registers 


Listing 6.4. Module D : Verilog alternative code with a parame¬ 
terized bit-size, following the TKGate 2 syntax. 

module D #(.N(1)) (Q, _Q, D, Ck, _P, _C); 

output [N-1:0] Q, _Q; 
input [N-l:0] D; 
input Ck, _P, _C; 
wire [N-1:0] wl, w2, w3, w4; 

// 

assign #6 wl = ~ (w3 & {N{Ck}} & {n{_C}}) ; // gl 


assign #6 w2 = ~ (wl & {N{Ck}} & w4); // g2 

assign #6 w3 = ~ ({n{_p}} & w4 & wl); // g3 

assign #6 w4 = ~(w2 & D & {n{_C}}) ; // g4 

assign #6 Q = ~ ({n{_P}} & wl & _Q) ; // g5 

assign #6 _Q = ~ (Q & w2 & {n{_C}}) ; // g6 

endmodule 



Preset 







300 


Registers 


Listing 6.7. Module JK1 : Verilog code instantiating the D mod¬ 
ule (listing 6.4) with the name ml . 


module JK1 

(Q, _Q, J, K, Ck, _P, _C); 


output 

Q, 

_Q; 


input J 


K, Ck, _P, _C; 


wire wl 

r 

w2 , D; 


// 




D #(1) 

ml 

(Qr _Q, D, Ck, _P, _C) ; 

// ml 

// 




assign 

#6 

wl = Q & ~K; 

// gl 

assign 

#6 

w2 = J & _Q; 

// g2 

assign 

#6 

D = wl w2; 

// g3 

// 




endmodule 





The figures appearing in the following sections might call the clock 
line either with the abbreviation Clk or Ck , but the flip-flops are 
meant to be edge-triggered, even if there is not the standard triangu¬ 
lar symbol for this purpose. 

6.1 Multiplexer 

To build a register is usually required to include one or more multi¬ 
plexers. The following figure and listing show a 2-to-l multiplexer, 
using NAND gates, where D n inputs and Y output lines have an un¬ 
specified size. 



Registers 


301 


Figure 6.8. 2-to-l multiplexer. 



A 

Listing 6.9. Module MUXltol : Verilog code for a 2-to-l multi¬ 
plexer conforming to the previous figure. 

module MUX2tol #(.N(1)) (Y, DO, Dl, A); 

output [N-1:0] Y; 
input [N-1:0] DO, Dl; 
input A; 

wire [N-1:0] wl, w2; 

// 

assign #4 wl = ~ (DO & {n{~A}}) ; // gl 

assign #4 w2 = ~ (Dl & {n{a}}) ; // g2 

assign #4 Y = ~(wl & w2) ; // g3 

endmodule 


6.2 Simple data register 

The simplest register is the one that can load a multi-bit value, stor¬ 
ing it until the input lines are enabled again. In the following figure, 
the value stored by the register can be read from the output lines £? 3 „ 0 

























302 


Registers 


and a new value can be loaded from the input lines D 3 o. The input 
value is loaded only when the input Load is asserted, otherwise the 
flip-flops just reload the previous value at every clock positive edge. 



Registers 


Figure 6.10. 4-bit register: when the Load input line is asserted 
and a positive edge clock is reached, the register loads the value 
available from the input lines / 3 0 , otherwise the previous stored 
value is just kept as it is. 







304 


Registers 


To allow a better understanding, the following figure shows how the 
register works when it is willing to receive the input data, removing 
the logic that switches the data sources: 



When the register keeps the previous stored value, it works like the 
following figure: 



I should be clear that the D flip-flop inputs are switched by a multi¬ 
plexer, as the following figure can clarify: 











Registers 


305 


Qn Dn 



The simple data register has an important feature: it can be updated 
starting from the value that it contains already, when the positive 
clock edge is received. The following figure shows a data registers 
that might load a new data from a combinational circuit, which cal¬ 
culate something on the current register value: 










Registers 


307 


The register output is connected to a combinational circuit that trans¬ 
forms the data in some unspecified way. The combinational circuit 
then feeds the register when the Load input is asserted and the clock 
reaches the positive edge. In practice this circuit does what could be 
formally written as x=f(x), or x^f(x) if the RTL notation (register 
transfer level ) is used. 

Figure 6.15. n-bit data register. 

D 

V 



c 

Listing 6.16. Module DR : Verilog code for a data register reusing 
the modules D (listing 6.4) and MUX2tol (listing 6.9), conform¬ 
ing to the previous figure. 

module DR #(.N(1)) (Q, D, L, Ck, _P, _C) ; 

output [N-1:0] Q; 
input [N-l:0] D; 


















308 


Registers 


input L, Ck, _P, _C; 


wire [N-1:0] wl, _Q; 


// 


MUX2tol #(N) ml (wl, Q, D, 

L) ; 

D #(N) m2 (Q, _Q, wl, Ck, 

_P, _C); 

endmodule 



6.3 Shift register 

The following figure shows a register that can receive a single logic 
value from the input SD (serial data), when there is a positive edge 
clock signal. At this time, the first flip-flop on the right updates its 
value with the serial data obtained by the input SD, whereas the 
second flip-flop updates itself using the previous value from the first 
flip-flop and the same thing happens to the other flip-flops. 



Registers 


309 


Figure 6.17. 4-bit shift register: when there is a positive edge 
clock signal, the input value is stored inside the first flip-flop on 
the right, whereas the second gets the old value from the first 
one, and so it continues up to the last flip-flop. Video: ogv http:/ 
/www.youtube.com/watch 7v=I_ncbpQnCZ4 . 



Q3 Q2 Q1 Q0 


< Preset 


<SD 


< Clear 


<Clk 



A shift register, like the one that appears in the previous figure, can 
be extended so that it can load a value. In that case a Load input can 
be added to switch the register flip-flops, like the following figure 
shows. 








































310 


Registers 


Figure 6.18. 4-bit shift register with parallel load: when the input 
Load is asserted and the clock signal reaches the positive edge, 
the register stores the value that is available at the input Z> 3 „ 0 , 
otherwise, if the input Load is negated, each flip-flop is updated 
with the last value from the previous one, except the first that is 
updated from the serial input. 


Load SD Preset Clear Clk 

V V V V V 
































































Registers 


311 


6.4 Asynchronous counter with T flip-flop 

The counters are registers that increment or decrement their binary 
value at every clock pulse; the asynchronous ones contain flip-flops 
that are not connected to the same clock signal. The easiest counter 
is made of T flip-flops, because this kind of flip-flop, when the T in¬ 
put is asserted, inverts the output value each time it receives a clock 
pulse. The following figures show the use of cascaded T flip-flops, 
which means that each clock input is driven by the output of a pre¬ 
vious one: that is why these are asynchronous counters. 


Figure 6.19. 4-bit increasing asynchronous counter: the next flip- 
flop is driven by the Q output from the previous one. Video: ogv 
http://www.youtube.com/watch 7v=-mfL6B0w9UI . 


f 



Preset 


Q 


T 

Q 


Clk 


Clear 




4 

Preset 

Q 

T 

Q 

Clk 

Clear 



Preset 


Q 



T 

Q 



Clk 


Clear 




Preset 


Q 



T 

Q 



Clk 


Clear 



/ dd 


-< Preset 




-<Clk 


■< Clear 


V 

Q3 


v 

Q2 


V 

Q1 


V 

QO 











































312 


Registers 


Figure 6.20.4-bit decreasing asynchronous counter: the next flip- 
flop is driven by the Q output from the previous one. Video: ogv 
http://www.youtube.com/watch ?v=fvhina5QEnI . 




Q3 Q2 Q1 Q0 


Asynchronous counters have the disadvantage that each binary digit 
is updated with a little delay, which is added to the next one. 


6.5 Synchronous T flip-flop counters 

Synchronous counters can be builded with T flip-flop, but in a dif¬ 
ferent way from what is described in the previous section. However, 
when these counters need to be modified to allow a parallel binary 
load, D flip-flops should be used instead. 











































Registers 


313 


Figure 6.21. 4-bit synchronous counter based on T flip- 
flops: the outputs are synchronous, but a little later than the 
clock impulse. Video: ogv http://www.youtube.com/watch?v= 
Nh5CzRopNdY . 



Q3 Q2 Q1 QO 


< Preset 


<Clk 


< Clear 




The synchronous counter requires that the T input of the first flip- 
flop remains always asserted. However, controlling that input it is 
possible to pause the counting process, without clearing the current 
value. Therefore it is possible to add an enable input, controlling the 
T input of the first flip-flop, as the following figure shows in red. 















































































































































314 


Registers 


Figure 6.22. 4-bit synchronous counter with enable input (En). 




f 



Y 

Preset 

U 

1 

Q 

Clk 

Clear 


t 


Y 

Q3 



Preset 


< En 


<Clk 


< Clear 


To obtain a decreasing counter it is enough to invert the outputs of 
each T flip-flop involved. 

Figure 6.23. 4-bit decreasing synchronous counter, with enable 
input. 



6.6 Synchronous counters with D flip-flops 

It is generally more convenient to build synchronous counters using 
D flip-flops, as they can be easily extended to allow a parallel binary 
load. This section shows only equivalent examples of the previous 
one (with D flip-flops), but the following section is then related to 
the parallel load. 






























































































Registers 




Figure 6.24. 4-bit ascending synchronous counter, with enable 
input, made of D flip-flops. 



Figure 6.25. 4-bit decreasing synchronous counter, with enable 
input, made of D flip-flops. 

< En 



< Preset 











316 


Registers 


Figure 6.26. Alternative 4-bit decreasing synchronous counter, 
with enable input, made of D flip-flops. 



Q3 Q2 Q1 QO 


< En 


< Preset 


< Clk 


< Clear 


It is important to understand the logic added to the D flip-flops, 
which is made of simple half-adders or half-subtractors. 







Registers 


317 


Figure 6.27. The ascending synchronous counter contains a half¬ 
adder. 



Q 


























































318 


Registers 


Figure 6.28. The decreasing synchronous counter contains a half¬ 
subtractor. 



Q 

The D flip-flops might be represented in a compact, parallel draw, 
where the ports D, Q and Q are bit vectors. In that case also the 
counter can be shown in a more compact way. The following fig¬ 
ure shows the use of a full-adder and a full-subtractor, because they 
allow to follow the concept in an easier and immediate way. 

























































Registers 


319 


Figure 6.29. Compact representations. 



The compact representation allows to understand how to extend and 
possibly to simplify the logic. The following example replaces the 
enable input with the value to be added at each clock signal, value 
that might be either positive or negative, or even zero if no change 
should be applied. 










































320 


Registers 



Figure 6.30. More general counter with variable increment. 



6.7 Synchronous counters with parallel load 

The counter is complete only if it allows the parallel data load. The 
following figures show counters based on D flip-flops, allowing the 
parallel data load. 























Registers 


321 


Figure 6.31. 4-bit synchronous counter with parallel data load: 
the input Load allows to load the value received by the inputs 
D 3 .o into the flip-flops; otherwise, if the Load input is negated, 
the input En allows to increment or keep unchanged the previous 
value stored inside the register. 

En Load Preset Clk Clear 















Registers 


Figure 6.33. 4-bit synchronous increasing and decreasing 
counter: the input/ allows to select if the counter should increase 
or decrease. 


En 


f f-0: inc 


Preset 


Clk Clear 







324 


Registers 


Figure 6.34. 4-bit synchronous counter with parallel load: this is 
a simpler solution, where the increment value is free and might 
be positive, negative or zero. 






























“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


325 

Bus and control unit 


Chapter 


7.1 Tri-state buffer . 325 

7.2 Hardcoded bus control unit. 329 

7.3 Microcode . 334 


bus 325 325 enable 325 load 325 microcode 334 tri-state buffer 325 


Registers and combinational circuits are often grouped together, 
joining a set of connections (wires). This set of connections is what 
is known as bus. A bus where different components have the ability 
to write to and read from is usually a data bus , because it is used to 
exchange data between the components; however, it should be no¬ 
ticed that only one component at a time should be allowed to write 
to the bus, whereas for reading there is no limitation. 

7.1 Tri-state buffer 


A data bus can be implemented with a multiplexer or with tri-state 
buffers , which are components similar to buffers or inverters (de¬ 
pending on the type), but with an additional input that is used either 
to enable the output or to isolate it. The following figure shows the 
tri-state buffer compared to a traditional switch: 




0 = open circuit 
1 = closed circuit 













326 


Bus and control unit 


Tri-state buffers or multiplexers, are necessary to control the bus 
writing. The tri-state buffer method is simpler and cheaper than the 
multiplexer, because the multiplexer would require more logic gates 
and a longer propagation delay. 

The following figures show the adaptation of a simple data register, 
using a tri-state buffer to connect it to a bus; then this kind of register 
is shown connected with others on a data bus, controlled by a control 
bus. 



Bus and control unit 


Figure 7.2. Simple data register adaptation for a data bus. 


bus read 


Preset 


Clear Clk bus write 








328 


Bus and control unit 


Figure 7.3. Simplified diagrams for the same register adaptation. 
The input bus_read , or br , is used to load and store the bus value 
into the register, whereas the input bus_write , or bw, allows the 
register to write its stored value to the bus. 



Bus3 0 0 0 ObusO 

Bus2 Busl 


Here are used the definitions “bus read” and “bus write”, to identify 
respectively the actions to load a value from the bus and to put a 
value to the bus; however, some more formal documentation, when 
referring to registers, prefer the definitions “load” and “enable” in¬ 
stead, because the register loads data or is enabled to write its data. 









































Bus and control unit 


329 


Figure 7.4. Different components connected to the bus: the con¬ 
trol inputs used to enable reading or writing the bus, together 
with other potential control inputs, are connected to a secondary 
bus (the control bus). The second draw shows an alternative way 
to represent the connections to the control bus, picking a wire at 
a time. 



7.2 Hardcoded bus control unit 


To direct properly the data bus usage it is necessary a control unit , 
which should be responsible to mark the phases of every process that 
is to be applied. To understand the problem the following diagram is 



















































330 


Bus and control unit 


used (which is already appeared in the previous section), where three 
components communicate through a data bus, under the direction of 
a control bus (only data transfer operations are considered). 


Figure 7.5. Three components communicating through a data 
bus. 



To mark the operation steps, the control unit needs a counter. There 
are two main types of control units, the first one is hardcoded , the 
second is microcoded. The hardcoded control unit requires a shift 
counter, which can be implemented as the following figure shows. 
What should be noticed reading the timing diagram is that the output 
control lines are active (asserted) before the clock impulse used to 
drive the data bus components: to obtain this result, the clock pulse 
used by the counter is inverted. 






























Bus and control unit 


331 


Figure 7.6. Shift counter used by the control unit: the clock signal 
is inverted, so that the output lines T n are already active when the 
clock positive margin reaches the data bus components. Video: 
ogv http://www.youtube.com/watch?v=vXco4E4SNTo . 



The hardcoded control unit should put together a function decoder 
with the shift register outputs. For example, the function// of the di¬ 
agram should do the following: copy A to B, then copy B to C: the 
decoder activates the second line (labeled//), then, with some AND 
gates the outputs Aw and Br are activated when the shift counter has 















































































































332 


Bus and control unit 


the T o output active, then, the same way, the outputs Bw and Cr are 
activated when the shift counter has the T i output active. The out¬ 
puts Aw , Br , Bw and Cr, activated at the proper time, following the 
shift counter direction, would enable the registers read-write, allow¬ 
ing the programmed data transfer. The control unit implementation 
that appears in the following figure is extremely simplified and the 
T 2 time is not even used; however, the time J 3 is used instead to 
stop the clock signal related to the control unit itself, which should 
be cleared to be able to accept a new command from the input/. 



Bus and control unit 


333 


Figure 7.7. Control unit: only four simple functions are avail¬ 
able, for which two times are sufficient; therefore the time T 2 is 
unused and the time T 3 locks the control unit until the Run input 
is cleared and reactivated. Video: ogv http://www.youtube.com/ 
watch ?v=r-DZgjy-yaO . 


Clk 



TO 

T1 

T2 


(T2 is not used) 

















































































334 


Bus and control unit 


Figure 7.8. Control unit connected to the components that 
should drive. Video: ogv http://www.youtube.com/watch?v=kp 
ET2kEcUIo . 



7.3 Microcode 


The implementation of a hardcoded control unit is a complex work. 
For that reason is usually preferable a ROM memory (read only), 
divided into two parts: the map and the microcode. The two parts 
of the memory should be seen as two tables: the first one translates 
the desired function into an address to the second table, where the 
code for the related procedure starts. Please see the following figure, 
where on the left there is the control unit diagram and on the right 
there is the counter implementation. 





































Bus and control unit 


335 


Figure 7.9. Control unit implemented with ROM memories: on 
the left appears the control unit block diagram and on the right 
there is the detailed four-bit counter (the counter can be in¬ 
cremented or can load a new value). Video: ogv http://www. 
youtube.com/watch7v=mBGhNP3Uujs . 



CON 



























336 


Bus and control unit 


Load 


Clear 


D 



Q 


The two ROM memories are named, respectively, mO and ml . In the 
following figure is shown the content of these memories, using ta¬ 
bles, associating the memory address input (A) with the correspond¬ 
ing value that is returned from the memory data output (D). The 
mO memory of these examples uses only two bits for the addresses, 
which correspond to the function requested to the control unit that 
is known as operation code or opcode , whereas the data output has 
a 4-bit range, which in turn is the address for the ml memory, con¬ 
taining the microcode. 


























































































Bus and control unit 


337 


Figure 7.10. Memory contents and links between them. 

m 0 m l 

fo 

f, 
f* 

/, 


The output from the mO memory is assigned to a counter; the counter 
output is used to access to the ml memory; the ml memory output 
is the microcode word used to control the bus and the same control 
unit itself. To allow a better understanding of the process, the various 
steps are listed below, assuming that the function f \ (opcode) has 
been requested. 

1. When the system is started, the Run input is equal to 0 
(zero), which involves the counter reset to zero. As the counter 
starts from zero, from the ml memory is selected the value 
000000010 2 , which is the initial microcode word. The active bit 
of the microcode word is used to request the counter to load the 
value that comes from the memory mO (0011 2 ), which produces 
the value corresponding to the address that represent the input 
function (f i = 01 2 ). 






338 


Bus and control unit 


2. Activating the Run input, at the clock negative edge (the global 
clock is inverted for the control unit) the counter loads the address 
from the mO memory (0011 2 ) and offers the same value to the 
ml memory as an address. The ml memory produces the value 
000110000 2 as the new microcode word, which corresponds to 
the request to copy the register A to B . 

3. At the next clock negative edge the counter is incremented, se¬ 
lecting from the ml memory the address 0100 2 which gives the 
value 011000000 2 , which in turn corresponds to the request to 
copy the B content into C. 

4. At the next clock negative edge the counter is incremented again, 
selecting from ml the value corresponding to the address 0101 2 , 
which is 000000111 2 , which in turn corresponds to the request to 
clear the counter, loading the fixed value 0000 2 , and to suspend 
the clock signal received by the control unit. 

At this point, the execution cycle of a function is finished, but to 
start another cycle after another function is selected, it is necessary 
to disable and enable again the input Run . 



Bus and control unit 


339 


Figure 7.11. Connection between the control unit and the other 
data bus components: the first three lines from the control bus 
are used inside the control unit itself and these are not useful to 
drive the data bus modules. 



The ROM memories that are used in a control unit can be coded 
with the help of tools that allow a symbolic notation. For example, 
TKGate has a special compiler that produces map and microcode 
image files, starting from a single source file. Please notice that the 
function requested to the control unit are defined as labels inside 
the opcode map memory. The following source listing is compatible 
with the examples of this section. 

Listing 7.12. Opcode and microcode following the TKGate 2 
syntax. 

// MEMORIES: 

map bank[1:0] mO; 

microcode bank[8:0] ml; 

// - 




































340 


Bus and control unit 


// MICROCODE WORD'S FIELDS: 

field ctrl_start [ 0]; 

// set the address to 0 

field ctrl_load[1]; 

// load the counter 

field stop [ 2]; 

// stop the clock 

field a_br[3] ; 

// A <— bus 

field a_bw[4]; 

// A —> bus 

field b_br[5] ; 

// B <— bus 

field b_bw[6] ; 

// B —> bus 

field c_br[7] ; 

// C <— bus 

field c_bw[8] ; 

// C —> bus 

//- 


// FUNCTIONS = OPCODES: 


op f 0 { 


map f 0: 0; 


+0[7:0]=0; 


}; 


op f 1 { 


map f1: 1; 


+0[7:0]=1; 


}; 


op f2 { 


map f 2: 2; 


+0[7:0]=2; 


}; 


op f 3 { 


map f 3: 3; 


+0[7:0]=3; 


}; 


//- 







Bus and control unit 


341 



The map memory content is organized in opcodes: the operation 
code is the address in which is located inside the map memory; for 
example, the function f 2 has the opcode 2 (10 2 ): 



342 


Bus and control unit 


op f2 { 

map f 2: 2; 

+ 0 [ 7 : 0 ]= 2 ; 

}; _ 

The figure that connects the mO and ml memories appears again 

below, with the addition of other details, to conclude the topic. 
Figure 7.14. Map (opcodes) and microcode. 

172 opcode /77 i microcode 

U map 1 


address 

content 

0 

000000010 

load counter 

1 

000110000 

B< — A 

2 

000000111 

load zero, stop clock 

3 

000110000 

B< — A 

4 

011000000 

C< — B 

5 

000000111 

load zero, stop clock 

6 

011000000 

C< — B 

7 

000000111 

load zero, stop clock 

8 

011000000 

C< — B 

9 

100001000 

A < — C 

10 

000000111 

load zero, stop clock 










“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


Chapter 

TKGate 2 introduction and troubleshooting 


8.1 Modules . 344 

8.2 Module library or cut and paste between files . 347 

8.3 Bit-size . 350 

8.4 Cut and paste troubles . 352 

8.5 File PostScript and EPS . 352 


8.6 Multiplexers, demultiplexers and encoders depiction_ 353 

bit-size 350 bit-width 350 copy and paste 352 cut and paste 352 
EPS 352 module 344 paste 352 PostScript 352 TKGate 343 


TKGate 2 1 (http://www.tkgate.org ) is a Verilog design and simula¬ 
tion environment, which allows to make logic circuit programming 
starting from the graphical view, allowing even an easier Verilog 
testing. TKGate is well documented, but it might be difficult at the 
beginning to put all the things together and, unfortunately, some¬ 
times it does not work precisely as expected and some bugs need to 
be known. 


There is a substantial difference between versions 1 and 2, but 
even if version 2 is not yet finished, this is the one that should be 
chosen, because of its coherence with Verilog. 

Before using TKGate 2 to build a significant project, even if the 
intention is to work entirely in a graphic way, it is very important to 








344 


TKGate 2 introduction and troubleshooting 


know the Verilog basics, because all the concepts used by TKGate 
are taken from the Verilog language. 

The video ogv http://www.youtube.com/watch?v=ROEFsizmibY 
shows how TKGate 2 can be used to draw and test simple circuits, 
where some mistakes are made deliberately to get warnings from 
the simulator. Please notice that the files produced by TKGate are 
Verilog sources with special comments, instantiating predefined TK¬ 
Gate’s modules. 

8.1 Modules 

TKGate requires to organize the work into modules. There is at least 
the top level module , which is usually named main : a different name 
might be given to the top level one, but it is better to avoid this 
change. The top level module is the one that is run when the sim¬ 
ulation is started and, for that reason, is not instantiated. 

A simple circuit can be designed directly inside the top level mod¬ 
ule, but usually it is better to divide the work into small modules, 
especially if they can be reused. The TKGate’s module is exactly a 
Verilog one, but with an additional interface used to describe how 
this module should be seen graphically. 

When a module is created, like the example of the following figure, 
it is defined as a Verilog module, with the addition of comments to 
describe the graphical location of the components. 


TKGate 2 introduction and troubleshooting 


345 


Figure 8.1. A simple NOR SR latch module. 

go 



Listing 8.2. The code used by TKGate 2 to describe the module 
appearing in the above figure: at the moment the external graph- 
ical interface of the module is not defined. _ 

//: /netlistBegin srl 
module srl (Q, R, S, _Q); 

//: interface /sz:(40, 40) /bd:[ ] /pd: 0 /pi: 0 /pe: 0 /pp: 1 
output Q; //: /sn:0 {0}(360, 169) (368, 169){1} 

//: {2}(372, 169) (402, 169){3} 

//: {4}(370, 171) (370, 184) (321,184) (321,216) (339,216){5| 

output _Q; //: /sn:0 {0}(339, 171) (328, 171) (328, 194) (375, 194) (375,217){1} 

//: {2}(377,219) (402,219){3| 

//: {4} (373, 219) (366, 219) (366,219) (360,219){5| 

input R; //: /sn:0 {0}(302,166) (320,166) (320,166) (339, 166){1} 

input S; //: /sn:0 {0}(302,221) (320,221) (320,221) (339, 221){1} 

//: enddecls 

//: OUT g4 (Q) @(399,169) /sn:0 /w:[ 3 ] 

//: IN g3 (R) @(300,166) /sn:0 /w:[ 0 ] 

//: IN g2 (S) @(300,221) /sn:0 /w:[ 0 ] 

_GGNOR2 #(4) gl (.I0(Q), .I1(S), .Z(_Q)); //: @(350,219) /w:[ 5 1 5 ] 

//: OUT g6 (_Q) @(399,219) /sn:0 /w:[ 3 ] 

//: joint gl (_Q) @(375, 219) /w:[ 2 1 4 -1 ] 

//: joint g5 (Q) @(370, 169) /w:[ 2 -1 1 4 ] 

_GGNOR2 #(4) gO (.I0(R), .11(_Q), .Z(Q)); //: @(350,169) /w:[ 1 0 0 ] 


endmodule 

//: /netlistEnd 






346 


TKGate 2 introduction and troubleshooting 


The above Verilog code contains the instantiation of NOR gates, but 
in that case TKGate uses its own special module _GGNOR2. 

When the module interface (the module container) is described 
graphically, then the code is changed with this new data, replacing 
the original empty declaration. 

Listing 8.3. The graphical module wrapper is defined by a special 
Verilog comment. 

//: /netlistBegin srl 
module srl(Q, R, S, _Q); 

//: interface /sz:(60, 48) /bd:[ LiO>R(33/48) Lil>S(12/48) ^ 
^RoO<Q(12/48) Rol<_Q(34/48) ] /pd: 0 /pi: 0 /pe: 0 /pp: 1 

endmodule 

//: /netlistEnd 


The interface might be retouched with a text editor program, for ex¬ 
ample to set a particular size for better aesthetics. Anyway, when 
changing manually a TKGate file, a copy should be made before, 
because TKGate might not be able to understand the new one. 

The modules created directly as Verilog code work just like the other 
ones, except that the module internals can not be shown as circuits, 
but there is the advantage that behavioural code might be used and 
that the code editing might be done directly inside the TKGate file. 
Even in that case the modules require the graphical interface defini¬ 
tion, so that a box with wires can be drawn. 





TKGate 2 introduction and troubleshooting 


347 


Listing 8.4. A Verilog module for TKGate 2. 

//: /hdlBegin sr2 

//: interface /sz:(60, 48) /bd:[ LiO>R(33/48) Lil>S(12/48) RoO<Q(12/48) ^ 
^Rol<_Q (34/48) ] /pd: 0 /pi: 0 /pe: 0 /pp: 1 

//: enddecls 

module sr2 (_Q, Q, S, R); 
output Q, _Q; 
input S, R; 

nor # (4) gO (Q, R, _Q) ; 
nor # (4) gl (_Q, S, Q) ; 
endmodule 
//: /hdlEnd 


Please notice that for TKGate the graphical modules are netlist mod¬ 
ules , whereas the other type are defined as HDL modules. 

This video ogv http://www.youtube.com/watch?v= 

RFC9VYHEuWA shows the creation and instantiation of SR latch 
modules, as netlist and as HDL, using different ways for creating 
or copying the graphical interface, and even for changing the aspect 
ratio. 

8.2 Module library or cut and paste between files 

A module type can be copied inside the same TKGate file, probably 
with the purpose of changing something inside the new copy, but a 
module copy from a different file is not an intuitive task to do. There 
are two ways: including a ‘library’ or using a manual cut and paste 
with a text editor. 

TKGate allows to access other files, treating them as module li¬ 
braries. A library file can be any TKGate file containing modules 
(other modules than the top level one) and should be located in a 
directory that is meant to contain such libraries. The paths for the 



348 TKGate 2 introduction and troubleshooting 

directories that are intended to contain libraries are defined with the 
command Tool, Options , Libraries , Path. 

Figure 8.5. Library path configuration. 


File Edit Tool Simulate Format Module Components Help 


q ^ j |SMove/Connect 
* \>Cut Wire 
! ^Invert 




M Tree j^Bit Width 

k[S) Replicate 

Libre— 


Opti^p 


ns... 


Nets Ports 


FI 

F2 

F3 

F5 


Ctl-r 



A library file can be included using the command File, Library man¬ 
ager , or with the library icon as the following picture shows. 
























TKGate 2 introduction and troubleshooting 


349 


Figure 8.6. Library inclusion. 


File Edit Tool Simulate Format Module Components Help 


yD & 

[* v 




ftn sn ii 

Open the library manager. 

O t^dits: 1 ^ lype: wire 



fU II o ^ Ip a 3 Jis 

[ II ^ 1^[ II Technology: default 


|^| Tree |i| List 

i-cl 

Pi main 

E^{ j Libraries 

74XXX-0318 
0 | D7483 
0 t d7483 
0 | D7485 
0 S D74138 
0 S d74138 
0 | D74139 
0 S d74139 
0 S D74148 
0 | D74150 


D_ _IIj 

Nets 

Ports 





TkGate: Circuit Properties 

- 

General 

Libraries 

Scripts Simulation 



Circuit Properties 



Select libraries required by 
this circuit. Library 
requirements are saved 
with the circuit and will be 
automatically loaded the 
next time you load this 
circuit. 


6^74XXX-0318 [load] - "74XXX" 

□ coke - "Coke Machine Interface" 

□ timer - "Ocillators and One-Shots with absolute time delays” 

□ tty - "Interactive TTY Device" 


OK Cancel 


The modules from an included library can be instantiated as if they 
were common modules, but these modules can also be ‘claimed’, 
which means that they can be copied inside the current TKGate 
file. If the modules form external libraries are claimed, the li¬ 
brary can also be released (unloaded). The video ogv http://www. 
youtube.com/watch?v=8QlsTGcMLlU shows the inclusion of a li¬ 
brary, where a module is used, claimed and then the library itself is 
released. 


If a module from another file should be included, it might be cut and 
pasted with a text editor program, but this method works only if the 
original module does not instantiate any non-standard modules, or if 
these extra modules are already available (and compatible). 


























350 

8.3 Bit-size 


TKGate 2 introduction and troubleshooting 


Wires can carry a single or multiple binary digits, but there is a limit 
that can not be exceeded with TKGate 2: 999. However, when wires 
are connected to switches and LEDs (used to test the modules), this 
value should not be higher than 32; moreover, in some other cases 
the limit is even lower: 31 bits. 

It is important to notice also that the bit-width should always be 
Tittle-endian’ and starting from 0, which in this field means that 
should always be declared as [n : 0], where n is a positive number, 
equal to width -1. 

Working graphically with TKGate’s built-in components, the bit- 
size might be changed using different methods, but not all of them 
work always: sometimes these components are turned into input- 
output ports. When this problem arises, the bit-width should be 
changed accessing the configuration of the component itself. 

Figure 8.7. The single switch should drive only a single bit. 




ft, 

on 


ft 

on 

8 

/ 


•• •• 

off 

L J 

— — 

off 

/ 



Figure 8.8. The dip-switch can drive up to 32 bit: it can produce 
values from 00000000i6 to FFFFFFFFi 6 . 
























































TKGate 2 introduction and troubleshooting 


351 


Figure 8.9. Reduction logics can accept only up to 31 bit-wide 
input. 


ON 

OFF 


31 


> 


-D 


ON 

OFF 


32 




-D 


Figure 8.10. The input inversion with a ‘bubble’ might not work 
with multiple-bit connections. 



Figure 8.11. TKGate includes built-in modules to simulate RAM 
and ROM memories: the address input should not exceed 31 bits. 



Figure 8.12. The ROM or RAM data output can not be wider than 
32 bits. 

































































































































































































352 TKGate 2 introduction and troubleshooting 

8.4 Cut and paste troubles 


A whole circuit or a little piece of it might be copied, either inside the 
same module or into another one. If the copy is related to a portions, 
it might happen that TKGate pastes a wrong netlist, so that it is not 
able to save the file anymore. As it is not easy to predict this problem, 
after a cut-paste or copy-paste action, it is important to verify if it is 
possible to save: if it is not, the pasted circuit must be removed and 
a different way should be tried. 


Figure 8.13. TKGate is not able to save: maybe the last paste is 
not working fine and should be removed. 



The video ogv http://www.youtube.com/watch?v=http://www. 
youtube.com/JGKxcDzyt44 shows a copy and paste that works and 
another one that does not. 


8.5 File PostScript and EPS 

The circuits drawn with TKGate might be ‘printed’, producing 
PostScript or EPS files. The PostScript or EPS files generated by 




































TKGate 2 introduction and troubleshooting 353 

TKGate 2.0-blO have a flaw that do not allow Ghostscript to work 
properly. See the following PostScript/EPS code: 


/Courier-Latini /Courier findfont defLatinl 
/Courier-Bold-Latini /Courier-Bold findfont defLatinl 

/Courier—Italic-Latinl /Courier-Italic findfont defLatinl 
/Courier-Boldltalic-Latinl /Courier-Boldltalic findfont defLatinl 

/Helvetica-Latini /Helvetica findfont defLatinl 

/Helvetica-Bold-Latini /Helvetica-Bold findfont defLatinl 

/Helvetica-Oblique-Latini /Helvetica-Oblique findfont defLatinl 

The lines appearing with a darker character produce a fatal error 
with Ghostscript, but it is possible to comment them out to avoid the 
problem, without harming the final typographical result: 


/Courier-Latini /Courier findfont defLatinl 
/Courier-Bold-Latini /Courier-Bold findfont defLatinl 

%/Courier-Italic-Latinl /Courier-Italic findfont defLatinl 
%/Courier-Boldltalic-Latinl /Courier-Boldltalic findfont defLatinl 

/Helvetica-Latini /Helvetica findfont defLatinl 

/Helvetica-Bold-Latini /Helvetica-Bold findfont defLatinl 

/Helvetica-Oblique-Latini /Helvetica-Oblique findfont defLatinl 

To correct these files it is possible to make a script, using SED with 
a command like this: 

$ cat file.ps^ 

^ | sed "s/ A \/Courier-Italic/%\/Courier-Italic/g"^> 

^ | sed "s/ A \/Courier-BoldItalic/%\/Courier-BoldItalic/g"^ 

^ > fix.ps [Enter] 

8.6 Multiplexers, demultiplexers and encoders 
depiction 

TKGate includes some built-in modules, especially multiplexers, de¬ 
multiplexers and encoders. These components are shown graphically 




354 


TKGate 2 introduction and troubleshooting 


with numbered ports, which is important to identify each line. These 
special modules can be configured, for example specifying the port 
order; however, when these modules are printed, the port number¬ 
ing that appears in the PostScript/EPS file might be wrong. To avoid 
the printing problem, it is better to put a graphical comment with 
the port order, then the PostScript code responsible for the wrong 
numbering should be removed. 

Inside the PostScript or EPS file, every component has its own ‘func¬ 
tion’, declared inside the prolog. The following code extract shows 
the functions related to multiplexer and similar components, where 
the wrong code is commented out: 


/mux { 


dup /mrot exch def 
startgate 
8 rfont 

-29.5 15.5 moveto 

29.5 15.5 lineto 

16.5 -12.5 lineto 
-16.5 -12.5 lineto 
closepath stroke 

dup % n n 

1 add 58 exch div % n dl 

2 copy mul % n dl dn 

mrot -90 eq mrot -180 eq or { 

% 3-1 roll 1 sub 50 string cvs exch (0) exch % dl (n) (0) dn 

% -29 add 7 rCT % dl 

% exch -29 add 7 rCT 


% 


% 


% 


} { 

3 -1 roll 1 sub 50 string cvs exch 

-29 add 7 rCT 

(0) exch -29 add 7 rCT 


% dl (n) dn 


% dl 


} ifelse 
grestore 


} def 



TKGate 2 introduction and troubleshooting 


355 


/demux { 

startgate 
8 rfont 

(demux) 0 5 rCT 
-16.5 12.5 moveto 

16.5 12.5 lineto 

29.5 -15.5 lineto 
-29.5 -15.5 lineto 
closepath stroke 

dup % n n 

1 add 58 exch div % n dl 

2 copy mul % n dl dn 

% 3-1 roll 1 sub 50 string cvs exch % dl (n) dn 

% -29 add -12 rCT % dl 

% (0) exch -29 add -12 rCT 

grestore 


} def 


/decoder { 

startgate 
8 rfont 
(dec) 0 5 rCT 
-16.5 12.5 moveto 

16.5 12.5 lineto 

29.5 -15.5 lineto 
-29.5 -15.5 lineto 
closepath stroke 

dup % n n 

1 add 58 exch div % n dl 

2 copy mul % n dl dn 

% 3-1 roll 1 sub 50 string cvs exch % dl (n) dn 

% -29 add -12 rCT % dl 

% (0) exch -29 add -12 rCT 

grestore 
} def 


The PostScript or EPS code can not be corrected otherwise, because 
these functions do not receive a parameter telling them the right port 



356 

order. 


TKGate 2 introduction and troubleshooting 


Figure 8.17. Multiplexer, decoder and demultiplexer: on the left 
with the original port numbering, which might be wrong; on the 
right without port numbering. 



1 Tkgate GNU GPL 














“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


Traditional logic integrated circuits 


Data distributors or demultiplexers . 359 

74138 3-to-8 data distributor or demultiplexer . 359 

74139 dual 2-to-4 data distributor or demultiplexer . 361 

74154 4-to-16 data distributor or demultiplexer . 365 

74238 3-to-8 data distributor or demultiplexer . 369 

Data selectors or multiplexers. 372 

74150 l-of-16 data selector or multiplexer . 372 

74151 l-of-8 data selector or multiplexer . 377 

74153 dual l-of-4 data selector or multiplexer . 380 

74157 quad l-of-2 data selector or multiplexer . 384 

Special circuits. 387 

74148 8-to-3 priority encoder . 387 

Arithmetic units. 392 

7483 4-bit binary full-adder . 392 

7485 4-bit magnitude comparator . 396 

74181‘a’ALU . 401 

74181 ‘b’ ALU . 407 

74182 carry lookahead generator . 413 

74381 4-bit ALU . 416 

74382 4-bit ALU . 422 


357 






















74138 359 74139 362 74148 387 74150 372 74151 377 74153 380 
74154 365 74157 384 74181 401 407 74182 413 74238 369 74381 
416 74382 422 7483 392 7485 396 


358 


Data distributors or demultiplexers 

74138 3-to-8 data distributor or demultiplexer 


« 


« 


74138 truth table. 


e 2 

El 

Eo 

A 2 

A, 

Aq 

y 7 

y 6 

Ys 

y 4 

y 3 

y 2 

Yi 

Yo 

X 

X 

1 

X 

X 

X 

1 

1 

1 

1 

1 

1 

1 

1 

X 

1 

0 

X 

X 

X 

1 

1 

1 

1 

1 

1 

1 

1 

0 

X 

X 

X 

X 

X 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

0 

1 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

0 

0 

0 

1 

0 

1 

1 

1 

1 

1 

0 

1 

1 

1 

0 

0 

0 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

0 

0 

1 

0 

0 

1 

1 

1 

0 

1 

1 

1 

1 

1 

0 

0 

1 

0 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

0 

0 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 

1 

1 

0 

0 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 


359 














(1) 4 

@ 

AO ^ Vcc 

CD 

(2) — 

A1 

YO 

— (15) 

(3) — 

A2 

Y1 

■ 4 - (14) 

( 4 ) 

EO Y2 

i74138 

— (13) 

(S) _ 

El 

Y3 

(12) 

(6) 

E2 

Y4 

4- (11) 

< 7 > ^ 

Y7 

Y5 

4- (10) 

(8) — 

GND 

Y6 

4- 0) 


TOP VIEW 



~QQ 


_A _A A 

EO El E2 



EO 

eT 



E2 > 


->°- 



£ 

£ 

£ 

£ 

± 

£ 

£ 

7 



4 - 


> 


A- YO 
A> Y1 
>- Y2 
A> Y3 

A> Y4 

> Y5 
A- Y6 

> Y7 


^ Y 


360 

































































































































74138 Verilog code. 

module h74138 (_Y, A, _E0, _E1, E2); 

input [2:0] A; 
input _E0, _E1 , E2; 
output [7:0] _Y; 

// 

function [7:0] f74138 (input [2:0] A, input _E0, 

input _E1, input E2) ; 
if (_E0 == 0 && _E1 == 0 && E2 == 1) 
begin 


case 

(A) 


0: 

f74138 = 

8'blllllllO; 

1: 

f74138 = 

8'bllllll01; 

2 : 

f74138 = 

8'blllllOll; 

3: 

f74138 = 

8'bllll0111; 

4 : 

f74138 = 

8'blll01111; 

5: 

f74138 = 

8'bll011111; 

6 : 

f74138 = 

8'blOllllll; 

7 : 

f74138 = 

8'bOlllllll; 


endcase 


end 

else 

begin 

f74138 = 8'bllllllll; 
end 

endfunction 

// 

assign #8 _Y = f74138 (A, _E0, _E1, E2); 

endmodule 


361 




74139 dual 2-to-4 data distributor or demultiplexer 


One half 74139 truth table. 


( 1 ) 

( 2 ) 

(3) 

(4) 

(5) 

( 6 ) 

(7) 

( 8 ) 



TOP VIEW 


Eb 


362 









































^ Ya 


^ Yb 


74139 Verilog code. 

module h74139 (_Ya, _Yb, Aa, Ab, _Ea, _Eb); 
input [1:0] Aa, Ab; 
input _Ea, _Eb; 
output [3:0] _Ya, _Yb; 

// 

function [3:0] f74139 (input [1:0] A, input _E); 

if (_E == 0) 
begin 

case (A) 


363 

















































































































0: 

f7413 9 = 

4'blllO 

1: 

f7 413 9 = 

4'bll01 

2 : 

f7 413 9 = 

4'bl011 

3: 

f7413 9 = 

4'b0111 


endcase 

end 

else 

begin 

f74139 = 4'bllll; 
end 

endfunction 

// 

assign #8 _Ya = f74139 (Aa, 
assign #8 _Yb = f74139 (Ab, 
endmodule 


_Ea) ; 
_Eb) ; 


364 




74154 4-to-16 data distributor or demultiplexer 


74154 truth table. 


Ei E0A3A2A1A0 y 15 fi 4 f 13 f i 2 r hF 10 y 9 r 8 Yj f 6 f 5 f 4 f 3 r 2 f 0 


1 

1 

X 

X 

X 

X 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

X 

X 

X 

X 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

X 

X 

X 

X 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

0 

0 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

0 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

0 

1 

0 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

0 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

0 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 


365 






(1) 

◄- 

YO 

@ 

Vcc 

— (24) 

(2) 

◄- 

Y1 


AO 

^ (23) 

(3) 

◄- 

Y2 


A1 

^ (22) 

(4) 

◄- 

Y3 


A2 

— (21) 

(5) 

◄- 

Y4 


A3 

— (20) 

(6) 

◄- 

Y5 

i74154 

El 

— 09) 

(7) 

◄- 

Y6 


EO 

— (18) 

(8) 

◄- 

Y7 


Y15 

— 07) 

(9) 

◄- 

Y8 


Y14 

— (16) 

(10) 

◄- 

Y9 


Y13 

(15) 

(11) 

~i r 

Y10 


Y12 

— 04) 

(12) 

-► 

GND 


Y11 

— (13) 



EO El 


366 

































































74154 Verilog code. 

module h74154 (_Y, A, _E0, _E1); 

input [3:0] A; 
input _E0, _E1; 
output [15:0] _Y; 

// 

function [15:0] f74154 (input [3:0] A, 

input _E0, input _E1); 
if (_E0 == 0 && _E1 == 0) 


367 








































































































































































begin 


case 

(A) 

0: 

f74154 

1: 

f74154 

2 : 

f74154 

3: 

f74154 

4 : 

f74154 

5: 

f74154 

6: 

f74154 

7 : 

f74154 

8: 

f74154 

9: 

f74154 

10: 

f74154 

11: 

f74154 

12 : 

f74154 

13: 

f74154 

14 : 

f74154 

15: 

f74154 


endcase 
end 
else 
begin 
f7 4154 
end 

endfunction 

// 

assign #8 _Y 
endmodule 


16'blllllllllllllllO; 

16'bllllllllllllll01; 

16'blllllllllllll011; 

16'bllllllllllll0111; 

16'blllllllllll01111; 

16'bllllllllll011111; 

16'blllllllll0111111; 

16'bllllllll01111111; 

16'blllllll011111111; 

16'bllllll0111111111; 

16'blllll01111111111; 

16'bllll011111111111; 

16'blll0111111111111; 

16'bll01111111111111; 

16'bl011111111111111; 

16'b0111111111111111; 


16'bllllllllllllllll; 


f7 4154 (A, _E0, _E1); 


368 




74238 3-to-8 data distributor or demultiplexer 


74238 truth table. 


e 2 

E x 

Eo 

A 2 

Ax 

Aq 

y 7 

y 6 

y 5 

y 4 

y 3 

y 2 

Yx 

Yo 

X 

X 

1 

X 

X 

X 

0 

0 

0 

0 

0 

0 

0 

0 

X 

1 

0 

X 

X 

X 

0 

0 

0 

0 

0 

0 

0 

0 

0 

X 

X 

X 

X 

X 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

1 

0 

1 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

1 

0 

0 

1 

0 

0 

0 

1 

1 

0 

0 

0 

0 

1 

0 

0 

0 

1 

0 

0 

1 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

1 

0 

1 

0 

0 

1 

0 

0 

0 

0 

0 

1 

0 

0 

1 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

1 

0 

0 

1 

1 

1 

1 

0 

0 

0 

0 

0 

0 

0 


(1) - 

@ 

AO ^ Vcc 

(16) 

(2) — 

A1 

YO 

- (15) 

(3) - 

A2 

Y1 

- (14) 

W ♦ 

EO Y2 

i74238 

„ (13) 

(S) + 

El 

Y3 

. (12) 

(6) 

E2 

Y4 

— (11) 


Y7 

Y5 

— (10) 

(8) —+ 

GND 

Y6 

- (9) 


TOP VIEW 


YO 



'W 


^ Y1 
^ Y2 
^ Y3 

^ Y4 

^ Y5 
^ Y6 

Y7 


_A _A A 

EO El E2 


369 




























































74238 Verilog code. 


module h74238 (Y, A, _E0, _E1, 

input [2:0] A; 
input _E0, _E1 , E2; 
output [7:0] Y; 

// 

E2) ; 


function [7:0] f74238 (input 

[2:0] 

A, 

input 

_E0, 

input _E1, 

input 

E2) ; 


if (_E0 == 0 && _E1 == 0 && 
begin 

case (A) 

E2 = 

: = 1) 

0: f74238 = 8'b00000001; 


1: f74238 = 8'b00000010; 


2: f74238 = 8'b00000100; 



370 





















































































3 

f74238 = 8'b00001000; 

4 

f74238 = 8'bOOOlOOOO; 

5 

f74238 = 8'bOOlOOOOO; 

6 

f74238 = 8'b01000000; 

7 

f74238 = 8'blOOOOOOO; 

endcase 

end 


else 


begin 


f74238 = 8'b00000000; 

end 


endfunction 

// 

assign #8 

Y = f74238 (A, _E0, _E1, E2); 

endmodule 



371 




Data selectors or multiplexers 

74150 1 -of-16 data selector or multiplexer 

74150 truth table. 


E D\£)\J)\E)\J)\J)\E)<)D%DiD6D5D/[D?,D2D\DoA? ) A2A\Aq y 


0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

0 

0 

0 

0 

0 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

0 

0 

0 

0 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

0 

X 

0 

0 

0 

1 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

X 

0 

0 

0 

1 

0 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

0 

X 

X 

0 

0 

1 

0 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

X 

X 

0 

0 

1 

0 

0 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

0 

X 

X 

X 

0 

0 

1 

1 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

X 

X 

X 

0 

0 

1 

1 

0 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

0 

X 

X 

X 

X 

0 

1 

0 

0 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

X 

X 

X 

X 

0 

1 

0 

0 

0 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

0 

X 

X 

X 

X 

X 

0 

1 

0 

1 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

X 

X 

X 

X 

X 

0 

1 

0 

1 

0 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

0 

X 

X 

X 

X 

X 

X 

0 

1 

1 

0 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

X 

X 

X 

X 

X 

X 

0 

1 

1 

0 

0 

1 

X 

X 

X 

X 

X 

X 

X 

X 

0 

X 

X 

X 

X 

X 

X 

X 

0 

1 

1 

1 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

1 

X 

X 

X 

X 

X 

X 

X 

0 

1 

1 

1 

0 

1 

X 

X 

X 

X 

X 

X 

X 

0 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

0 

0 

1 

1 

X 

X 

X 

X 

X 

X 

X 

1 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

0 

0 

0 

1 

X 

X 

X 

X 

X 

X 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

0 

1 

1 

1 

X 

X 

X 

X 

X 

X 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

0 

1 

0 

1 

X 

X 

X 

X 

X 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

1 

0 

1 

1 

X 

X 

X 

X 

X 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

1 

0 

0 

1 

X 

X 

X 

X 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

1 

1 

1 

1 

X 

X 

X 

X 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

1 

1 

0 


372 




E 

Di£>iJ)i£)iJ)iiPi(P9DsD7D 6 D 5 D4D : 

i D^E) \ Do A. 2 

> A 2 A 

i Ao 

Y 

1 

X 

X 

X 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 0 

0 

1 

1 

X 

X 

X 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 0 

0 

0 

1 

X 

X 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 0 

1 

1 

1 

X 

X 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 0 

1 

0 

1 

X 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 1 

0 

1 

1 

X 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 1 

0 

0 

1 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 1 

1 

1 

1 

1 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 1 

1 1 

1 

0 


(1) 

-► 

D7 

@ 

Vcc 

(2) 

-► 

D6 


D8 

(3) 

-* 

D5 


D9 

(4) 

-► 

D4 


DIO 

(5) 

-► 

D3 


Dll 

(6) 

-► 

D2 

i74150 

D12 

(7) 

-► 

D1 


D13 

(8) 

-► 

DO 


D14 

(9) 

-► 

E 


D15 

(10) 

◄- 

Y 


AO 

(11) 

-► 

A3 


A1 

(12) 

-► 

GND 


A2 


(24) 

(23) 

( 22 ) 

( 21 ) 

( 20 ) 

(19) 

(18) 

(17) 

(16) 

(15) 

(14) 

(13) 


DO > 
D1 > 
D2> 
D3 > 
D4> 
D5 > 

D6> 
D7 > 
D8 > 
D9> 
DIO > 
Dll > 
D12 > 
D13 > 
D14 > 
D15 > 



373 































































A 

E 


374 





























































































































































































74150 Verilog code. 


module h74150 (_Y, D, A, E); 

input [15:0] D; 

input [3:0] 

A; 

input E; 


output _Y; 


// 


function f74150 (input [15:0] D, input [3:0] A, 


input E); 

if (E == 

1) 

begin 


case 

(A) 

0 

f74150 = ~D [0]; 

1 

f74150 = ~D [1]; 

2 

f74150 = ~D [2]; 

3 

f74150 = ~D [3]; 

4 

f74150 = ~D [4]; 

5 

f74150 = ~D [5]; 

6 

f74150 = ~D [6]; 

7 

f74150 = ~D [7]; 

8 

f74150 = ~D [8]; 

9 

f74150 = ~D [ 9]; 

10 

f74150 = ~D [10]; 

11 

f74150 = ~D [11]; 

12 

f74150 = ~D [ 12]; 

13 

f74150 = ~D [13]; 

14 

f74150 = ~D [14]; 

15 

f74150 = ~D [15]; 

endcase 


375 





end 

else 

begin 

f74150 = 1; 
end 

endfunction 

// 

assign #8 _Y = f74150 (D, A, E) ; 

endmodule 


376 



74151 l-of-8 data selector or multiplexer 


74151 truth table. 


E 

£>7 

De 

d 5 

Z>4 

d 3 

d 2 


Do 

4.2 

Ai 

4o 

Y 

Y 

0 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

X 

1 

0 

1 

X 

X 

X 

X 

X 

X 

X 

0 

0 

0 

0 

1 

0 

1 

X 

X 

X 

X 

X 

X 

X 

1 

0 

0 

0 

0 

1 

1 

X 

X 

X 

X 

X 

X 

0 

X 

0 

0 

1 

1 

0 

1 

X 

X 

X 

X 

X 

X 

1 

X 

0 

0 

1 

0 

1 

1 

X 

X 

X 

X 

X 

0 

X 

X 

0 

1 

0 

1 

0 

1 

X 

X 

X 

X 

X 

1 

X 

X 

0 

1 

0 

0 

1 

1 

X 

X 

X 

X 

0 

X 

X 

X 

0 

1 

1 

1 

0 

1 

X 

X 

X 

X 

1 

X 

X 

X 

0 

1 

1 

0 

1 

1 

X 

X 

X 

0 

X 

X 

X 

X 

1 

0 

0 

1 

0 

1 

X 

X 

X 

1 

X 

X 

X 

X 

1 

0 

0 

0 

1 

1 

X 

X 

0 

X 

X 

X 

X 

X 

1 

0 

1 

1 

0 

1 

X 

X 

1 

X 

X 

X 

X 

X 

1 

0 

1 

0 

1 

1 

X 

0 

X 

X 

X 

X 

X 

X 

1 

1 

0 

1 

0 

1 

X 

1 

X 

X 

X 

X 

X 

X 

1 

1 

0 

0 

1 

1 

0 

X 

X 

X 

X 

X 

X 

X 

1 

1 

1 

1 

0 

1 

1 

X 

X 

X 

X 

X 

X 

X 

1 

1 

1 

0 

1 


(1) 

@ 

D3 

Vcc 

◄- 

(16) 

DO > 

(2) ^ 

D2 

D4 

◄- 

(15) 

D1 > 

< 3 > - 

D1 

D5 

◄- 

(14) 

D2> 

( 4 ) — 

DO 

D6 

◄- 

(13) 

D3> 

( 5 ) -*■ 

174151 

Y 

D7 

◄- 

(12) 

D4> 

(6) -*r 

Y 

AO 

◄- 

(11) 

D5> 

( 7 ) — 

E 

A1 

◄- 

(10) 

D6> 

( 8 ) ^ 

GND 

A2 

◄- 

( 9 ) 

D7> 




E 

V 



377 


A 

A 







































A> - 7 ^ 



74151 Verilog code. 


module h74151 (Y, _Y, D, 

A, E); 

input [7:0] D; 


input [2:0] A; 


input E; 


output Y, _Y; 


// 


function f74151 (input 

[7:0] D, input [2:0] A, 

input 

E) ; 


378 




































































































if (E == 

= 1) 

begin 


case (A) 

0 

f74151 = D [0]; 

1 

f74151 = D [1]; 

2 

f74151 = D [2]; 

3 

f74151 = D [3]; 

4 

f74151 = D [4]; 

5 

f74151 = D [5]; 

6 

f74151 = D [6]; 

7 

f74151 = D [7]; 

endcase 

end 


else 


begin 


f74151 = 0; 

end 


endfunction 

// 


assign #8 

Y = f74151 (D, A, E); 

assign #8 

_Y = ~Y; 

endmodule 



379 





74153 dual l-of-4 data selector or multiplexer 


half 74153 truth table. 


E 

Ds 

d 2 

D 1 

D 0 

Ai 

Ao 

Y 

1 

X 

X 

X 

X 

X 

X 

0 

0 

X 

X 

X 

0 

0 

0 

0 

0 

X 

X 

X 

1 

0 

0 

1 

0 

X 

X 

0 

X 

0 

1 

0 

0 

X 

X 

1 

X 

0 

1 

1 

0 

X 

0 

X 

X 

1 

0 

0 

0 

X 

1 

X 

X 

1 

0 

1 

0 

0 

X 

X 

X 

1 

1 

0 

0 

1 

X 

X 

X 

1 

1 

1 


380 




Ea 


(1) 

( 2 ) 

(3) 

(4) 

(5) 

( 6 ) 

(7) 

(8) 



A 

A1 


381 





























































Ea > 
DaO > 

Dal > 

Da2 > 

Da3 > 

Eb > 
DbO > 

Dbl > 

Db2 > 

Db3 > 




t> 





Ya 


^ Yb 


2 

A> - 7^ 


1 

0 



74153 Verilog code. 

module h74153 (Ya, Yb, Da, Db, A, _Ea, _Eb); 
input [3:0] Da, Db; 
input [1:0] A; 
input _Ea, _Eb; 
output Ya, Yb; 

// 

function f74153 (input [3:0] D, input [1:0] A, 

input _E); 

if (_E == 0) 
begin 


382 






























































































case (A) 

0: f74153 = D [0]; 

1: f74153 = D [1]; 

2: f74153 = D [2]; 

3: f7 4153 = D[3]; 
endcase 
end 
else 
begin 

f7 4153 = 0; 
end 

endfunction 

// 

assign #8 Ya = f74153 (Da, A, _Ea); 
assign #8 Yb = f74153 (Db, A, _Eb); 
endmodule 


383 




74157 quad l-of-2 data selector or multiplexer 


74157 truth table. 


E 

Da n 

Db n 

A 

Y i, 

1 

X 

X 

X 

0 

0 

X 

0 

0 

0 

0 

X 

1 

0 

1 

0 

0 

X 

1 

0 

0 

1 

X 

1 

1 


(1) 

-► 

A @ 

Vcc 

(2) 

-► 

DaO 

E 

(3) 


DbO 

Da3 

(4) 

4 - 

Y0 

i74157 

Db3 

(5) 

-4 

Dal 

Y3 

(6) 


Dbl 

Da2 

(7) 

4 - 

Y1 

Db2 

(8) 

-4 

GND 

Y2 


(16) 

(15) 

(14) 

(13) 

( 12 ) 

( 11 ) 

( 10 ) 

(9) 


TOP VIEW 



A 

A 


384 





















A 

E 


^ Y 


74157 Verilog code. 


module h74157 (Y, 

Da, Db, A, _E); 

input [3:0] Da, 

Db; 

input A; 


input _E; 


output [3:0] Y; 


// 


function [3:0] 

f74157 (input [3:0] Da, 


input [3:0] Db, 


385 













































































































input A, input _E); 

if (_E == 0) 
begin 

case (A) 

0: f7 4157 = Da; 

1: f74157 = Db; 
endcase 
end 
else 
begin 

f74157 = 0; 
end 

endfunction 

// 

assign #8 Y = f74157 (Da, Db, A, _E); 
endmodule 


386 



Special circuits 

74148 8-to-3 priority encoder 


« 


The 74148 is a priority encoder with negated inputs and outputs. It 
has an enable input and an enable output, used to activate the encoder 
and to allow concatenation with other 74148 modules. The output 
selects the higher input index and the module concatenation starts 
from the higher input module, as the last picture shows. The output 
GS (group select) is asserted if at least an input D n is asserted. 


74148 truth table. 


Ei 

Z >7 

D 6 

d 5 

Z >4 

d 3 

d 2 


Do 

GS 

Eo 

y 2 

Y\ 

To 

1 

X 

X 

X 

X 

X 

X 

X 

X 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

0 

0 

X 

X 

X 

X 

X 

X 

X 

0 

1 

0 

0 

0 

0 

1 

0 

X 

X 

X 

X 

X 

X 

0 

1 

0 

0 

1 

0 

1 

1 

0 

X 

X 

X 

X 

X 

0 

1 

0 

1 

0 

0 

1 

1 

1 

0 

X 

X 

X 

X 

0 

1 

0 

1 

1 

0 

1 

1 

1 

1 

0 

X 

X 

X 

0 

1 

1 

0 

0 

0 

1 

1 

1 

1 

1 

0 

X 

X 

0 

1 

1 

0 

1 

0 

1 

1 

1 

1 

1 

1 

0 

X 

0 

1 

1 

1 

0 

0 

1 

1 

1 

1 

1 

1 

1 

0 

0 

1 

1 

1 

1 


387 




















Eo 

A 


( 1 ) 

( 2 ) 

(3) 

(4) 

(5) 

( 6 ) 

(7) 

( 8 ) 


D4 

@ 

Vcc 

◄- 

(16) 

D5 


Eo 

-► 

(15) 

D6 


GS 

-► 

(14) 

D7 

i74148 

D3 

◄- 

(13) 

Ei 


D2 

◄- 

(12) 

Y2 


D1 

◄- 

(11) 

Y1 


DO 

◄- 

(10) 

GND 


YO 

-► 

(9) 


DO 

D1 

D2 

D3 

D4 

D5 

D6 

D7 


> 

> 

> 

> 

> 

> 

> 

> 



t 


8 

Eo 

Y 


D w74148 



Ei 

GS 


t 



^ GS 


■>* YO 

^ Y1 
■>“ Y2 


A 

Ei 


TOP VIEW 



388 




















































































































































74148 Verilog code. 

module h74148 (_GS, _Eo, _Y, _Ei, _D); 

input _Ei; 
input [7:0] _D; 
output _GS, _Eo; 
output [2:0] _Y; 

// 

function [2:0] f74148y (input _Ei, 

input [7:0] _D); 

if (_Ei == 0) 
begin 

if (~_D & 8'bl0000000) 
f7414 8y = 3'b000; 
else if (~_D & 8'b01000000) 
f7414 8y = 3'b001; 
else if (~_D & 8'b00100000) 
f7414 8y = 3'b010; 
else if (~_D & 8'b00010000) 
f7414 8y = 3'b011; 
else if (~_D & 8'b00001000) 
f7414 8y = 3'bl00; 
else if (~_D & 8'b00000100) 
f7414 8y = 3'bl01; 
else if (~_D & 8'b00000010) 
f7414 8y = 3'bllO; 
else if (~_D & 8'b00000001) 
f7414 8y = 3'blll; 
else 

f7414 8y = 3'blll; 


389 



end 

else 

f7414 8y = 3'blll; 
endfunction 

function f74148gs (input _Ei, input [7:0] _D); 
if (_Ei == 1) 
f7 414 8gs = 1; 

else if (_D == 8'bllllllll) 
f7 414 8gs = 1; 
else 

f7 414 8gs = 0; 
endfunction 

function f74148eo (input _Ei, input [7:0] _D); 
if (_Ei == 1) 
f7 414 8eo = 1; 

else if (_Ei == 0 && _D == 8'bllllllll) 
f7 414 8eo = 0; 
else 

f7 414 8eo = 1; 
endfunction 

// 

assign #8 _Y = f74148y (_Ei, _D); 
assign #8 _GS = f74148gs (_Ei, _D); 
assign #8 _Eo = f74148eo (_Ei, _D); 
endmodule 


390 



A chain of two 74148. 


16 

D > - 7^ 


Eo 



Ei 


391 






































Arithmetic units 


« 


7483 4-bit binary full-adder 

The 7483 is a 4-bit binary full-adder with carry-lookahead. The input 
carry is labeled C 0 , whereas the output carry is C 4 . 


7483 truth table. 


a 3 

-4 2 

A, 

Ao 

Bi 

Bi 

B 1 

B 0 

Co 

c 4 

Si 

s 2 

s, 

So 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

1 

0 

1 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

0 

0 

0 

1 

0 

0 

1 

0 

1 

1 

1 

1 

1 

1 

0 

0 

1 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

1 

0 

0 

1 

1 

1 

1 

0 

0 

1 

1 

1 

1 

1 

1 

1 

1 

0 

0 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

0 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 

1 


392 




B 

V 


(1) 

-► 

A 3 

@ 

B 3 

◄- 

(16) 

(2) 

◄- 

S 2 


S 3 

-► 

(15) 

(3) 

-► 

A 2 


C 4 

-► 

(14) 

(4) 

-► 

B 2 


CO 

◄" 

(13) 

(5) 

-► 

Vcc 

i7483 

GND 


(12) 

(6) 

◄- 

SI 


BO 

◄- 

(11) 

(7) 

-► 

B 1 


AO 


(10) 

(8) 

-► 

A 1 


SO 

-► 

(9) 


TOP VIEW 


A 

V 



<co 


s 


393 


























- s 



7483 Verilog code. 


module h7483 (C4, 

S, A, B, CO); 

input [3:0] A, 

B; 

input CO; 


output C4; 


output [3:0] S; 


// 


assign #12 {C4, 

S} = A + B + CO; 

endmodule 



394 

















































































































































A chain of two 7483. 


co 

V 


B > 


A > 



V 


C8 


395 

























7485 4-bit magnitude comparator 

The 7485 is a 4-bit magnitude comparator that can be extended with 
other 7485 to increase the bit-size comparison. First are compared 
the inputs A and B , then, if they are equal, the values form ABO , 
BAO and EQO are used. The inputs ABO , BAO and EQO can be 
used to connect another 7485 which compares less significant digits. 


7485 truth table. 


A and B 

GTi 

EQi 

LTi 

GTo 

EQo 

LTo 

A=B 

0 

0 

0 

1 

0 

1 

A=B 

0 

0 

1 

0 

0 

1 

A=B 

0 

1 

0 

0 

1 

0 

A=B 

0 

1 

1 

0 

1 

0 

A=B 

1 

0 

0 

1 

0 

0 

A=B 

1 

0 

1 

0 

0 

0 

A=B 

1 

1 

0 

0 

1 

0 

A=B 

1 

1 

1 

0 

1 

0 

A>B 

X 

X 

X 

1 

0 

0 

A<B 

X 

X 

X 

0 

0 

1 


396 




(1) 

-► 

B3 

@ 

Vcc 

(2) 


LTi 


A3 

(3) 

-► 

EQi 


B2 

(4) 

-► 

GTi 

i7485 

A2 

(5) 

◄- 

GTo 


A1 

(6) 

◄- 

EQo 


B1 

(7) 

◄- 

LTo 


AO 

(8) 

-► 

GND 


BO 


TOP VIEW 


(16) 

(15) 

(14) 

(13) 

( 12 ) 

( 11 ) 

( 10 ) 

(9) 


AO > 
A1 > 
A2> 
A3 > 


0 ^ 

2 

3 


0 ^ 

1 

2 

3 


< BO 
<B1 
<B2 
<B3 





A 


E 

3 





LTi 



w7485 


EQi 





GTi 

LTo 

EQo 

GTo 


◄- 








< LTi 

< EQi 

< GTi 


V 


V V 


LTo EQo GTo 


397 

























7485 Verilog code: the output ports GTo , EQo and LTo do not 
react exactly in the same way when A and B are equal and the 
input ports GTi , EQi and LTi have incoherent values. 

module h7485 (GTo, EQo, LTo, A, B, GTi, EQi, LTi); 
input [3:0] A, B; 
input GTi, EQi, LTi; 
output GTo, EQo, LTo; 
wire GT, EQ, LT; 

// 


398 




























































































































































assign 

#6 

GT = 

A > B; 

assign 

#6 

EQ = 

A == B; 

assign 

// 

#6 

LT = 

A < B; 

assign 

#6 

GTo 

= EQ?GTi:GT; 

assign 

#6 

EQo 

= EQ?EQi:EQ; 

assign 

endmodule 

#6 

LTo 

= EQ?LTi:LT; 


399 



A chain of two 7485. 


A 

V 


/ / 8 


B 

V 


/ X 8 


Y 

LTo 


\/ 




/ 


/ 





4 

4 





E 

5 






LTi 



w7485 


EQi 






GTi 

LTo 

EQo 

GTo 


4 

4 

4 


\/ 


EQo GTo 


/ / 4 


A 


B 



LTi 


w7485 

EQi 



GTi 

LTo 

EQo 

GTo 


<LTi 

'< EQi 
-<GTi 


400 




























74181 'o' ALU 


The 74181 can work in four different modes, but not all of them have 
properly calculated values for the G and P ports, which should be 
used by a carry lookahead generator. Only two of the four working 
modes are taken into consideration in this chapter and the one de¬ 
scribed in this section has the ports A, B , F, G and P are “active 
low”: in this mode the output ports required by a carry lookahead 
generator are correctly working as expected. 

The 74181 has the AeqB output port that is almost useless: it be¬ 
comes active only when the F (or F) output is equal to 111 1 2 ; on 
the other hand, this ALU does not have an output for the overflow 
condition. 


74181 operation table. 


S 3..0 M 

Co 

G 4 F 3..0 

p 

G 

0000 0 

0 

A 



0000 0 

1 

A minus 1 



0000 1 

X 

A 



0001 0 

0 

A B 



0001 0 

1 

(A-B) minus 1 



0001 1 

X 

A B 



0010 0 

0 

AB 



0010 0 

1 

(AB minus 1 



0010 1 

X 

A+B 



0011 0 

0 

0000 

0 

1 

0011 0 

1 

mi 

1 

1 

0011 1 

0 

0000 

0 

1 

0011 1 

1 

0000 

1 

1 


401 










403 











































s> 


4 



404 























































































































































































































A 16-bit ALU with four 74181. 



G4 

405 



















































































A 16-bit ALU with four 74181 and the 74182 as carry lookahead 
generator. 

co v 



406 


W74182 




























































































74181 'b'ALU 


In this mode the 74181 works using the ports A, B and F as “active 
high” whereas the ports CO and C4 are “active low”, but this way 
the outputs G and P do not produce the correct value and should not 
be used. 2 


74181 operation table. 


S 3..0 

M 

Co 

c 4 

F 3..0 Xp 

Xg 

0000 

0 

0 


A plus 1 


0000 

0 

1 


A 


0000 

1 

X 


A 


0001 

0 

0 


( A+B ) plus 1 


0001 

0 

1 


A+B 


0001 

1 

X 


(A+B) 


0010 

0 

0 


(A+B) plus 1 


0010 

0 

1 


A+B 


0010 

1 

X 


AB 


0011 

0 

0 

0 

0000 

1 

0011 

0 

1 

1 

1111 

1 

0011 

1 

0 

0 

0000 

1 

0011 

1 

1 

1 

0000 

1 

0100 

0 

0 


A plus (AB) plus 1 


0100 

0 

1 


A plus (A-B) 


0100 

1 

X 


(A-B) 


0101 

0 

0 


A B plus (A+B) plus 1 


0101 

0 

1 


A-B plus (A+B) 


0101 

1 

X 


B 


0110 

0 

0 


A minus B 



407 






Xp Xg 







S3..0 

M 

Co 

C 4 F 3..0 

Ap Xg 

1111 

0 

0 

A 


1111 

0 

0 

A minus 1 


1111 

1 

X 

A 



(1) 

-► 

BO 

@ ,/ 

^ Vcc 

(24) 

(2) 


AO 

A1 

^ (23) 

(3) 

-► 

S3 

B1 

+ " (22) 

(4) 

-► 

S2 

A2 

^ (21) 

(5) 

-► 

SI 

B2 

— (20) 

(6) 

-► 

SO 

A3 

i74181 b 

«r- (19) 

(7) 

-► 

CO 

B3 

— (18) 

(8) 


M 

xg 

^ (17) 

(9) 

◄- 

FO 

C4 

— (16) 

(10) 

◄- 

FI 

Xp 

(15) 

(11) 

◄- 

F2 

AeqB 

ht- (14) 

(12) 

-► 

GND 

F3 

“ (13) 


A4> 

A7> 

A6> 

A5> 




<B4 

<B6 

<B7 

<B5 


C4 < 
Xg < 
Xp 


4 


4 



/ 

V B 

M 

◄- 

C4 

w74181b S 

◄- 

xg 

◄- 

Xp 

CO 


AeqB F 


4 


4 


4 

7^ 


< MO 


0^ 

1 

2 ^ 

3 


<S5 

<S7 

<S6 

<S4 


<C0 


V 

AeqBO 



1 

—> 

2 


3 



F4 

F5 

F6 

F7 


409 











































s> 


4 



410 

































































































































































































































A 16-bit ALU with four 74181: the carry lookahead generator 
can not be used when input and output data are used as “active 
high”, because the output ports G and P do not work properly. 



411 


G4 


11:8 

15:12 




















































































412 



74182 carry lookahead generator 



413 























































































































A 16-bit ALU with 74182 and other ICs 


V 



414 


W74182 





































































415 



74381 4-bit ALU 


The 74381 is a 4-bit ALU that uses the ‘G’ and 4 P’ values to allow 
the carry propagation. If a bigger bit-size is required, this component 
needs the 74182 for the carry lookahead. 


74381 truth table. 


Function 

S 2..0 

A3..0 

B 3..0 

Co 

F 3..0 

g 4 

P 4 

clear 

000 

xxxx 

xxxx 

X 

0000 

0 

0 

B minus A 

001 

0000 

0000 

0 

1111 

1 

0 

B minus A 

001 

0000 

0000 

1 

0000 

1 

0 

B minus A 

001 

0000 

1111 

0 

1110 

0 

0 

B minus A 

001 

0000 

1111 

1 

1111 

0 

0 

B minus A 

001 

1111 

0000 

0 

0000 

1 

1 

B minus A 

001 

1111 

0000 

1 

0001 

1 

1 

B minus A 

001 

1111 

1111 

0 

1111 

1 

0 

B minus A 

001 

1111 

1111 

1 

0000 

1 

0 

A minus B 

010 

0000 

0000 

0 

1111 

1 

0 

A minus B 

010 

0000 

0000 

1 

0000 

1 

0 

A minus B 

010 

0000 

1111 

0 

0000 

1 

1 

A minus B 

010 

0000 

1111 

1 

0001 

1 

1 

A minus B 

010 

1111 

0000 

0 

1110 

0 

0 

A minus B 

010 

1111 

0000 

1 

1111 

0 

0 

A minus B 

010 

1111 

1111 

0 

1111 

1 

0 

A minus B 

010 

1111 

1111 

1 

0000 

1 

0 

A plus B 

Oil 

0000 

0000 

0 

0000 

0 

0 

A plus B 

Oil 

0000 

0000 

1 

0001 

1 

1 

A plus B 

Oil 

0000 

1111 

0 

1111 

1 

0 

A plus B 

Oil 

0000 

1111 

1 

0000 

1 

0 

A plus B 

Oil 

1111 

0000 

0 

1111 

1 

0 

A plus B 

Oil 

1111 

0000 

1 

0000 

1 

0 

A plus B 

Oil 

1111 

1111 

0 

1110 

0 

0 


416 




Function 

S 2..0 

A 3..0 

B3..0 

Co 

F 3..0 

g 4 

Pa 

A plus B 

Oil 

mi 

1111 

1 

1111 

0 

0 

A ®B 

100 

0000 

0000 

X 

0000 

0 

0 

A ® B 

100 

0000 

1111 

X 

1111 

1 

1 

A ®B 

100 

mi 

0000 

X 

1111 

1 

0 

A ®B 

100 

nil 

1111 

X 

0000 

0 

0 

A + B 

101 

0000 

0000 

X 

0000 

0 

0 

A + B 

101 

0000 

1111 

X 

1111 

1 

1 

A+B 

101 

nil 

0000 

X 

1111 

1 

1 

A+B 

101 

nil 

1111 

X 

1111 

1 

0 

A B 

110 

0000 

0000 

X 

0000 

0 

0 

A B 

110 

0000 

1111 

X 

0000 

1 

1 

A B 

110 

nil 

0000 

X 

0000 

0 

0 

A B 

110 

nil 

1111 

X 

1111 

1 

0 

preset 

111 

0000 

0000 

X 

1111 

1 

1 

preset 

111 

0000 

1111 

X 

1111 

1 

1 

preset 

111 

nil 

0000 

X 

1111 

1 

1 

preset 

111 

nil 

1111 

X 

1111 

1 

0 


417 





(1) 

( 2 ) 

(3) — 

(4) — 

(5) — 

( 6 ) — 

(7) 

( 8 ) — 

(9) — 

( 10 ) — 


AO > 


A1 > 



@ 


^ (20) 

A2> 

A1 

Vcc 

A3 > 

B1 


A2 

— (19) 


AO 


B2 

— (18) 


BO 


A3 

<r- (17) 


SO 

i74381 

B3 

(16) 

G4 < 

SI 


CO 

^ (15) 

^ (14) 

P4 < 

S2 


P 

FO 


G 

(13) 


FI 


F3 

^ (12) 


GND 


F2 

— (11) 

FO < 


TOP VIEW FI ■< 


F2 < 
F3 <- 


0 ^ 

1 

2 

3 


0 _ 

J_ 

2 _ 

3 


o 

2 

3 


A 

B 

G4 S 

W74381 

P4 

F 

uu 


4 

4 

/ 



< BO 
<B1 
<B2 
<B3 


0 

1 

2 


<S0 

<S1 

<S2 


<C0 


418 




































419 



























































































































































































































































A 16-bit ALU with 74381 and other ICs 


V 



420 


W74182 





































































421 



74382 4-bit ALU 


74382 truth table. 


Function 

Slo 

A 3..0 

B3..0 

Co 

F 3..0 

OVR 

c 4 

clear 

000 

xxxx 

xxxx 

X 

0000 

1 

1 

B minus A 

001 

0000 

0000 

0 

1111 

0 

0 

B minus A 

001 

0000 

0000 

1 

0000 

1 

0 

B minus A 

001 

0000 

1111 

0 

1110 

0 

1 

B minus A 

001 

0000 

1111 

1 

1111 

0 

1 

B minus A 

001 

mi 

0000 

0 

0000 

0 

0 

B minus A 

001 

mi 

0000 

1 

0001 

0 

0 

B minus A 

001 

nil 

1111 

0 

1111 

0 

0 

B minus A 

001 

nil 

1111 

1 

0000 

0 

1 

A minus B 

010 

0000 

0000 

0 

1111 

0 

0 

A minus B 

010 

0000 

0000 

1 

0000 

0 

0 

A minus B 

010 

0000 

1111 

0 

0000 

0 

0 

A minus B 

010 

0000 

1111 

1 

0001 

0 

0 

A minus B 

010 

nil 

0000 

0 

1110 

0 

1 

A minus B 

010 

nil 

0000 

1 

1111 

0 

1 

A minus B 

010 

nil 

1111 

0 

1111 

0 

0 

A minus B 

010 

nil 

1111 

1 

0000 

0 

1 

A plus B 

Oil 

0000 

0000 

0 

0000 

0 

0 

A plus B 

Oil 

0000 

0000 

1 

0001 

0 

0 

A plus B 

Oil 

0000 

1111 

0 

1111 

0 

0 

A plus B 

Oil 

0000 

1111 

1 

0000 

0 

1 

A plus B 

Oil 

nil 

0000 

0 

1111 

0 

0 

A plus B 

Oil 

nil 

0000 

1 

0000 

0 

1 

A plus B 

Oil 

nil 

1111 

0 

1110 

0 

1 

A plus B 

Oil 

nil 

1111 

1 

1111 

0 

1 

A ®B 

100 

0000 

0000 

X 

0000 

0 

0 

A ®B 

100 

0000 

1111 

X 

1111 

0 

0 

A ® B 

100 

nil 

0000 

0 

1111 

0 

0 


422 




Function 

S 2..0 

A 3..0 

B3..0 

Co 

F 3..0 

OVR 

c 4 

A ®B 

100 

mi 

0000 

1 

1111 

1 

1 

A ®B 

100 

mi 

1111 

X 

0000 

1 

1 

A + B 

101 

0000 

0000 

X 

0000 

0 

0 

A + B 

101 

0000 

1111 

X 

1111 

0 

0 

A+B 

101 

nil 

0000 

X 

1111 

0 

0 

A + B 

101 

nil 

1111 

0 

1111 

0 

0 

A+B 

101 

nil 

1111 

1 

1111 

1 

1 

A B 

110 

0000 

0000 

X 

0000 

1 

1 

A B 

110 

0000 

1111 

X 

0000 

0 

0 

A B 

110 

nil 

0000 

X 

0000 

1 

1 

A B 

110 

nil 

1111 

0 

1111 

0 

0 

A B 

110 

nil 

1111 

1 

1111 

1 

1 

preset 

111 

0000 

0000 

X 

1111 

0 

0 

preset 

111 

0000 

1111 

X 

1111 

0 

0 

preset 

111 

nil 

0000 

X 

1111 

0 

0 

preset 

111 

nil 

1111 

0 

1111 

0 

0 

preset 

111 

nil 

1111 

1 

1111 

1 

1 


423 






(1) — 

@ 

A1 Vcc 

(20) 

(2) 

B1 

A2 

— (19) 

(3) 

AO 

B2 

— (18) 

(4) ^ 

BO 

A3 

— (17) 

(5) ^ 

so 63 

i74382 

(18) 

(6) + 

SI 

CO 

— (15) 

(7) 

S2 

C 4 

*-(14) 

(8) 

FO 

OVR 

— (13) 

(9) ^ 

FI 

F3 

— (12) 

(10) — 

GND 

F2 

*-(11) 


TOP VIEW 


AO > 
A1 > 
A2> 
A3>" 


C4 


OVR < 


FO 

FI 

F2 

F3 


0 ^ 

J_ 

2 ^ 

3 


<: 

i 


2 

<— 

3 


A 

B 

C4 S 

W74382 

OVR 

F 

uu 



4 

4 



< BO 
<B1 
<B2 
<B3 


<S0 

<S1 

<S2 


<C0 


424 




































425 



















































































































































































































































































A 16-bit ALU with four 74382 



426 
































































The input port B might be used as “active high” and the operation 
table should be modified reversing all the B values: the G and P 
output would work correctly. 

2 The input port B might be used as “active low” and the operation 
table should be modified reversing all the B values, but the G and P 
output would not work either. 


427 


428 



References 


« 


•Wikipedia, George Boole , http://en.wikipedia.org/wiki/George_ 
Boole 

• Wikipedia, Augustus De Morgan , http://en.wikipedia.org/wiki/ 
A ugustus_De_Morgan 

•Wikipedia, Maurice Karnaugh , http://en.wikipedia.org/wiki/ 
Maurice_Kamaugh 

• Albert Paul Malvino, Jerard A. Brown, Digital Computer Elec¬ 
tronics , Glencoe/Mcgraw-Hill http://www.amazon.it/Digital- 
Computer-Electronics-Albert-Malvino/dp/0028005945 

• Stephen Brown, Zvonko Vranesic, Fundamentals of Dig¬ 
ital Logic with Verilog Design , Mcgraw-Hill http://www. 
amazon.com/Fundamentals-Mcgraw-Hill-Electrical-Computer- 
Engineering/dp/0072823151 ; Flip-Flops, Registers, Counters, 
and a Simple Processor , http://highered.mcgraw-hill.com/sites/ 
dl/free/0072823151/56549hra23151_ch07.pdf 

• Olivier Carton, Circuits et architecture des ordinateurs , http:/ 
/www.liaLa.Jussieu.fr/-carton/Enseignement/Architecture/archi. 
pdf 

• Mark Gordon Arnold, Verilog Digital Computer Design: 
Algorithms to Hardware , Prentice Hall PTR http://www. 
amazon.com/Verilog-Digital-Computer-Design-Algorithms/dp/ 
0136392539 ; Verilog hardware description language , http:// 
www.pearsonhighered.com/samplechapter/0136392539.pdf 

• IEEE, IEEE standard verilog hardware description language , 


429 


http://www.google. com!starch ?q=IEEE+standard+verilog+ 
hardware+description+language 


430 


“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


Part ii 


Simple CPU 

« 

9 A simple 8-bit CPU: version “A”. 437 

9.1 Version “Al”: fetch and execution . 440 

9.2 Version “A2”: memory index . 475 

9.3 Version 4 A3”: general purpose registers. 488 

9.4 Version 4 A4”: ALU. 495 

9.5 Version 44 A5”: flags . 531 

9.6 Version 44 A6”: branching . 550 

9.7 Version “AT: stack. 562 

9.8 Version 44 A8”: I/O . 581 

10 Version 44 B”: optimization. 605 

10.1 Uniform registers. 608 

10.2 Module 44 RAM”. 610 

10.3 Module 44 SEL”. 615 

10.4 Module 44 ALU”. 615 

10.5 Module “TTY”: the terminal . 616 

10.6 Module “CTRL”: control unit . 622 

10.7 Memories, fields, arguments and opcodes. 626 

10.8 Microcode. 644 

10.9 Macrocode: routine call. 664 

10.10 Macrocode: keyboard input and screen output. 666 

10.11 Version “B2” . 668 


431 























11 Version “C”: 16-bit little-endian. 673 

11.1 General purpose 16-bit registers . 676 

11.2 Module “BUS”. 680 

11.3 Module “ALU”. 681 

11.4 Module “SEL”. 692 

11.5 Module “RAM”. 693 

11.6 Module “IRQ” . 695 

11.7 Module “IVT” . 707 

11.8 Module “CTRL” . 710 

11.9 Opcodes. 713 

11.10 Microcode. 742 

11.11 Interrupts management. 762 

11.12 Module “RTC”: real time clock. 765 

11.13 Module “TTY” . 766 

11.14 Module “HDD”. 772 

11.15 Macrocode: terminal usage example, through interrupts 
780 

12 Version “D”. 783 

12.1 General purpose registers . 786 

12.2 Module “VRw” . 790 

12.3 Module “RAM”. 793 

12.4 Module “ALU” and related submodules . 796 

12.5 Module “BUS”. 804 

12.6 Module “IRQ” . 805 

12.7 Modules “DfT. 807 


432 

























12.8 Module “IVT” . 809 

12.9 Module “RTC”: real time clock. 812 

12.10 Module “TTY” . 813 

12.11 Module “HDD”. 818 

12.12 Module “CTRL” . 824 

12.13 Memory and microcode fields . 830 

12.14 Opcodes. 836 

12.15 Microcode. 872 

12.16 Macrocode . 929 

13 Version “E”. 931 

13.1 General purpose modules . 934 

13.2 Module “MEM”. 941 

13.3 General purpose registers . 946 

13.4 Module “ALU” and related submodules . 950 

13.5 Module “BUS”. 958 

13.6 Module “IRQ” . 959 

13.7 Module “IVT” . 961 

13.8 Module “RTC”: real time clock. 962 

13.9 Module “TTY”. 963 

13.10 Module “HDD”. 968 

13.11 Module “CTRL” . 974 

13.12 Memory and microcode fields . 978 

13.13 Opcodes. 983 

13.14 Microcode. 1019 

13.15 Macrocode . 1058 


433 



























14 Version “F”: 32-bit registers, big-endian, privileges_ 1061 


14.1 General purpose modules . 1065 

14.2 Addition modules . 1069 

14.3 Multiple clock lines . 1073 

14.4 Bus. 1076 

14.5 Registers: simple and with post-increment. 1078 

14.6 Memory segmentation. 1080 

14.7 Module “DA”. 1082 

14.8 Module “CA”. 1083 

14.9 Modules “M” and “RAM” . 1084 

14.10 Module “IR” . 1090 

14.11 Module “MD” . 1091 

14.12 Module “IRQ”. 1093 

14.13 Module “IVT”. 1095 

14.14 Module “ALU” . 1096 

14.15 Module “FL” . 1105 

14.16 Module “TTY” . 1108 

14.17 Module “HDD”. 1113 

14.18 Module “CTRL”. 1119 

14.19 Memory and microcode fields . 1122 

14.20 Opcodes . 1125 

14.21 Data initialization. 1158 

14.22 Microcode. 1159 

14.23 Process mode and interrupts. 1190 

14.24 Macrocode example: ‘memcpy’ . 1191 

434 


























14.25 Macrocode example: TTY with interrupt . 1194 

14.26 Macrocode example: user and supervisor. 1197 

References. 1209 


435 





436 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


437 


Chapter 


A simple 8-bit CPU: version "A" 


9.1 Version “Al”: fetch and execution . 440 

9.2 Version “A2”: memory index. 475 

9.2.1 Loading instructions . 481 

9.2.2 Storing instructions . 483 

9.3 Version “A3”: general purpose registers . 488 

9.4 Version “A4”: ALU . 495 

9.4.1 Instruction “not”. 510 

9.4.2 Instruction “and” . 512 

9.4.3 Instruction “or”. 514 

9.4.4 Instruction “xor”. 516 

9.4.5 Instruction “lshl” and “lshr”. 518 

9.4.6 Instruction “ashl” and “ashr”. 521 

9.4.7 Instruction “rod” and “rotr”. 524 

9.4.8 Instruction “add” . 527 

9.4.9 Instruction “sub”. 529 

9.5 Version “A5”: flags. 531 

9.5.1 Instruction “rotcl” and “rotcr”. 539 

9.5.2 Instruction “add_carry”. 541 

9.5.3 Instruction “sub_borrow”. 546 

9.6 Version “A6”: branching. 550 

9.7 Version “A7”: stack . 562 























438 


A simple 8-bit CPU: version "A" 


9.7.1 Instruction “push” and “pop”. 576 

9.7.2 Instruction “call” and “return”. 578 

9.8 Version “A8”: I/O. 581 

9.8.1 Communication with asynchronous devices . 581 

9.8.2 I/O devices implementation. 583 

9.8.3 External appearance of the synchronous interfaces . 590 

9.8.4 Synchronous keyboard interface. 591 

9.8.5 Synchronous display interface. 593 

9.8.6 The CPU data bus with the I/O interfaces. 597 

9.8.7 Instruction “out”. 603 

9.8.8 Instruction “in”. 604 


fetch 440 macrocode 440 microcode 440 microcode word 440 
microinstruction 440 opcode 440 operation code 440 


Here is introduced the development of a simple CPU, gradually 
adding components and functions, up to a very simple computer. 
Initially, it is only a CPU with 8-bit registers, including those used 
for the addressing inside the RAM memory, which is thus limited to 
a maximum of 256 bytes. 


Attachments 

Description 

attachments/xcpu/xcpu-al. v 

TKGate Verilog netlist source file 
for the CPU version “Al”. 

attachments/xcpu/xcpu-al .gm 

TKGate microcode and 

macrocode source file for the 
CPU version “Al”. 

attachments/xcpu/xcpu-a2. v 

TKGate Verilog netlist source file 
for the CPU version “A2”. 


















A simple 8-bit CPU: version "A" 


439 


Attachments 

Description 

attachments/xcpu/xcpu-a2.gm 

TKGate microcode and 

macrocode source file for the 
CPU version “A2”. 

attachments/xcpu/xcpu-a3. v 

TKGate Verilog netlist source file 
for the CPU version ‘A3”. 

attachments/xcpu/xcpu-a3.gm 

TKGate microcode and 

macrocode source file for the 
CPU version “A3”. 

attachments/xcpu/xcpu-a4. v 

TKGate Verilog netlist source file 
for the CPU version “A4”. 

attachments/xcpu/xcpu-a4-not. 

gm 

attachments/xcpu/xcpu-a4-and. 

gm 

attachments/xcpu/xcpu-a4-or.gm 

attachments/xcpu/xcpu-a4-xor. 

gm 

attachments/xcpu/xcpu-a4-lsh.gm 

attachments/xcpu/xcpu-a4-ash. 

gm 

attachments/xcpu/xcpu-a4-rot.gm 

attachments/xcpu/xcpu-a4-add. 

gm 

attachments/xcpu/xcpu-a4-sub. 

gm 

TKGate microcode and 

macrocode alternative source 
files for the CPU version “A4”. 

attachments/xcpu/xcpu-a5. v 

TKGate Verilog netlist source file 
for the CPU version “A5”. 











440 


A simple 8-bit CPU: version "A" 


Attachments 

Description 

attachments/xcpu/xcpu-a5-rotc. 

gm 

attachments/xcpu/xcpu-a5-addc. 

gm 

attachments/xcpu/xcpu-a5-subb. 

gm 

TKGate microcode and 

macrocode alternative source 
files for the CPU version “A5”. 

attachments/xcpu/xcpu-a6. v 

TKGate Verilog netlist source file 
for the CPU version “A6”. 

attachments/xcpu/xcpu-a6.gm 

TKGate microcode and 

macrocode source file for the 
CPU version “A6”. 

attachments/xcpu/xcpu-a7. v 

TKGate Verilog netlist source file 
for the CPU version “AT. 

attachments/xcpu/xcpu-a7-push- 

pop.gm 

attachments/xcpu/xcpu-a7-call- 

return.gm 

TKGate microcode and 

macrocode alternative source 
files for the CPU version “A7”. 

attachments/xcpu/xcpu-a8. v 

TKGate Verilog netlist source file 
for the CPU version “A8”. 

attachments/xcpu/xcpu-a8-kbd. 

vpd.tcl 

TCL/Tk script related to the key¬ 
board module KBD. 

attachments/xcpu/xcpu-a8-dsp. 

vpd.tcl 

TCL/Tk script related to the screen 
module DSP. 

attachments/xcpu/xcpu-a8-out. 

gm 

attachments/xcpu/xcpu-a8-in.gm 

TKGate microcode and 

macrocode alternative source 
files for the CPU version ‘A8”. 


9.1 Version "A1": fetch and execution 

In its first attempt, the CPU consists only of registers useful to access 
the memory, to read the opcode that should be executed, as shown 














A simple 8-bit CPU: version "A" 

in the next figure. 


441 



442 


A simple 8-bit CPU: version "A" 


Figure 9.2. Simple CPU version “Al”. 







































































































A simple 8-bit CPU: version "A" 


443 


The simpler module that can be analyzed is the oscillator, which 
provides the clock signal. It is an oscillator constructed with a series 
of inverting logic gates, to create a propagation delay sufficient to 
produce an oscillation at a manageable frequency. To activate the 
oscillation is required an initial pulse, which, after a short time to 
zero, is activated permanently. The next figure shows the oscillator 
and the start pulse necessary for activation. It is important to note 
that the series of inverter gates must be in odd number, as if it were a 
single inverter gate, but with a long propagation delay. The result is 
then given to a frequency divider, composed in this case of a chain of 
synchronous T flip-flops; the output is made of many lines grouped 
together, each of which allows to select an oscillation at a different 
frequency. The frequency divider is initialized by the same initial 
pulse, starting from 0 on all output lines. In the case of the examples 
is used a very low frequency, obtained from the last stage of division. 


Figure 9.3. Oscillator used for the clock signal. 





















444 


A simple 8-bit CPU: version "A" 


Figure 9.4. Frequency divider used inside the oscillator module: 
the divider is made of 12 T flip-flop, but the figure shows only 
four of them. 



The initial impulse is produced by a component synthesized through 
the Verilog code because otherwise it would be necessary to use ana¬ 
log electronic components and their discussion is beyond the scope 
of this study. 





















































A simple 8-bit CPU: version "A" 


445 


Figure 9.5. Verilog code for TKGate, relative to the trigger mod¬ 
ule used to start the oscillation: the output is initially zero, and af¬ 
ter a brief moment it passes to one, thus remaining permanently. 

module one_up (Z); 
output Z; 
reg Z; 
initial 
begin 

Z = 1'bO; 

// wait 1 ms: the timescale is 1 ns 

# 1000000 ; 

// activate the output value 

Z = l'bl; 
end 

endmodule 

The control unit, contained in the CTRL module, is very similar to 
the one described in section 7.3, with the difference that the input 
is identified by the 8-bit variable 7 (the letter T stands for ‘instruc¬ 
tion’) and that the output has a much higher bit range, forcing to use 
two memory units in parallel. The counter that is used to scan the 
instructions in the final block of memory has a total of 16 bits, but 
for convenience, two 8-bit counters were used in cascade. The input 
7 of the control unit is fed by the IR register content (instruction 
register). 



446 


A simple 8-bit CPU: version "A" 


Figure 9.6. Control unit: first there is the 8-bit counter module 
(microprogram counter) based on D flip-flops; then it appears 
the detail of the counter, in two alternative implementations. 


i 

V 



CON 



































































A simple 8-bit CPU: version "A" 


447 



The modules IR , MAR and MDR , are simple data registers, con¬ 
structed with D flip-flops, connected to the bus through tri-state 
buffers. From these registers it is possible to pick up a copy of the 
value stored by an additional output, called data. The register IR 
0 instruction register ), already mentioned, has the purpose to keep the 
























































































































































448 


A simple 8-bit CPU: version "A" 


opcode that the control unit should execute; the register MAR ( mem¬ 
ory address register ) has the purpose to keep the memory address to 
which the memory is to be accessed; the register MDR (memory 
data register) is used to accumulate what is read from the memory 
for some reason or what is to be written to the memory. 



A simple 8-bit CPU: version "A" 


449 


Figure 9.7. Registers IR, MAR and MDR. The diagram on the 
right is a compact version of the same circuit. 


br Clr Clk data bw 



The PC module is a register similar to the others, with the difference 
that it may increase the value that it contains when the input Inc is 
















































































































450 


A simple 8-bit CPU: version "A" 


asserted. The register PC {program counter) is intended to contain 
the memory address of the next opcode to be executed. 

Figure 9.8. Counter register PC. The diagram on the right is a 
compact, equivalent circuit. 


Inc Clk 




























































































































































A simple 8-bit CPU: version "A" 


451 


The RAM module is substantially different from the others, as it 
contains the RAM used by the CPU. This memory is accessed 
through the address provided via the 8-bit Addr input, but also the 
content of the memory is organized in 8-bit cells. The module shares 
with the others the same inputs to control the data bus access, but 
when the RAM module receives the address and the data bus read 
is enabled, the value in memory is updated immediately (except for 
the propagation delay), without waiting until the clock pulse reaches 
a positive edge. 

The RAM module receives the address from the MAR register, 
which is dedicated to hold the memory address to which the memory 
access should be done. 


Figure 9.9. Module RAM. The logic network that controls the 
inputs br and bw, should prevent the simultaneous read and write 
of the data bus. 


br 

V 



8 

/ o bus 


+ + + 

br Addr bw 

RAM 

bus 

t 


A 

bw 
















452 


A simple 8-bit CPU: version "A" 


The first thing that the structure described above should do is to load 
an opcode instruction, followed by the execution of it: this is known 
as fetch cycle. In this structure the PC register contains the address 
of the instruction to be executed: this value must be transferred to 
the MAR register and the PC register is incremented: the instruc¬ 
tion is obtained from the RAM at the address specified by the MAR 
register and it is copied to the IR register. This can be summarized 
as follows: 

1 MAR^PC 

2. PC++ 

3. IR^RAM[MAR] 

The following figures show just three steps, pointing out the values 
of hr , bw and Inc inputs, with LEDs, which turn red when the line 
to which they are connected is activated. The figures show the time 
when the clock signal becomes active. 



A simple 8-bit CPU: version "A" 


453 


Figure 9.10. First phase: it is requested to the PC register to send 
its value to the data bus and to the MAR register to read it. This 
implements in practice the operation MAR ^ PC . 


n 

n] 

fcj] 

n 

r< 

y 

nl 

fcj] 


1G 

i 10 


In 

nl 

lS] 

In 

u 

n 

u 

nl 

tj\ 


1G 


i 10 


In 

u 

nl 

u 

n 

u 

n 

u 

nl 

u 


1G 1 10 





Fdiv| 

| FO 

M 

1 l + 

11 


















































































































































































454 


A simple 8-bit CPU: version "A" 


Figure 9.11. Second phase: it is requested to the PC register to in¬ 
crease by one. This implements in practice the operation PC++. 


a 

n 

y 

ri\ 

yj] 

n 

u 

r< 

u 

nl 

u 



16 

_| 10 



O 




stop 




? a- 

I 




-12- JJ- 


S_5_ 

























□□ 





clear 


31:0 32 

► -^- 1 


1 

o o - 

an 

L 

□□ 







































































































































































A simple 8-bit CPU: version "A" 


455 


Figure 9.12. Third phase: it is requested to the RAM to send the 
value at the address pointed by the MAR register to the data bus 
and it is requested to the IR register to load it. This implements 
in practice the operation IR^RAM\ MAR\. 



Within the control unit (the CTRL module) the time is marked in the 
same way, apart from the fact that the counters cnt are driven by an 
inverted clock signal, to anticipate the activation of the control lines 
with respect to the data bus. Initially the counters of the control unit 
are cleared, so that they point to the first microinstruction, which 
is the request to perform the operation MAR ^ PC . Then, the mi¬ 
crocode counter (the group of the two counters cnt) is incremented 
and the new value points to the second microinstruction, which is the 
request to increase the PC register. Then, there is a further counter 
increase, bringing to the microinstruction IR^r- RAM [MAR]. 















































































































































































456 


A simple 8-bit CPU: version "A" 


Figure 9.13. First phase: the counters of the control unit are reset 
and the initial microinstruction is MAR ^PC . 































































































A simple 8-bit CPU: version "A" 


457 


Figure 9.14. Second phase: the set of counters has been increased 
and the microinstruction produced is PC++. 


0 































































































458 


A simple 8-bit CPU: version "A" 


Figure 9.15. Third phase: the set of counters has been increased 
and the microinstruction produced is 7 /?a- RAM [MAR]. 


FO 

-► 



Fdiv 

~ ► 


/ 


11 




t 




f ft 

i * 



0 


-t>°- 


1 


-• CNT 


- TBL 


n 

:n 

n 

M 

u 

:iji 

u 

t 


16 




VZ7 


start 


15:*j 


0 


r .m: 

4 


J°L 


L 


C E 

cnt 


elk 

L 


Clr 


c 

elk 

D 

cnt 

E 

L 

( 


Clr 



4 



/ 

"8 



—j— ^dd 


15:#J0 


_r 


jump to instruction execution 


_T 


35:3£ 


' 32 



Ji 


1 

- + - 

$sr32 


/ '*36 


At this point, the control unit has received the opcode from the input 
I and it is ready to execute it. To do this, the next microinstruction 
requires the microcode counter to accept the input value. This value 
is the content of the memory bank mO at the address represented by 































































































A simple 8-bit CPU: version "A" 


459 


the opcode itself. The value obtained from the memory bank mO is 
the microcode address to be executed. In the examples of the figures, 
the opcode is OOOOOOOO2 that is named not_operate (do nothing). 

Figure 9.16. Fourth phase: the counters of the control unit are 
loaded with the value from the memory bank that translates the 
opcode instruction into a microcode address. 


0 






























































































460 


A simple 8-bit CPU: version "A" 


Figure 9.17. Final phase: the counters of the control unit have 
been increased and point to the next microinstruction. Since the 
original instruction (not_operate) did not require the perfor¬ 
mance of any operation in the data bus, the current microinstruc¬ 
tion requires to the microcode counter group to reset to zero. The 
reset is done by loading the counters with zero through the mul¬ 
tiplexer that controls the input of these counters. 


ON 

OFF 


n 

u 


F 0 

-t 

JsciUKttJ^ 


Fdiv 

► 

/ 


/ 


11 

32 


i 


0 


-o°- 




* ft 

• 4 



i 


- CNT 


TBL 


n 

u 


n 

u 


u 

I 


16 


O 


vZ7 


start 




15:^101 ' 


I, 


c 

Clk 

L 


ent 


clr 


I 

l 

c 

E 

Clk cnt 

L 

C 

Clr 

) 


4 

/ 

'8 


~j —^dd 


1S:'6: 0 


_r 


jump to instruction execution 


17 


35:3£:Kr' 


1 


ii 

> 

4 

35 : 3 


32 


^6 






















































































A simple 8-bit CPU: version "A" 


461 


After resetting the counters of the control unit, it all starts from the 
initial microcode (the first three phases) which requires to load a 
new instruction. During the fourth phase (jump to the microcode 
execution of the requested opcode) and during the final phase (jump 
to the microcode implementing the initial fetch cycle), inside the 
data bus nothing happens. 

Figure 9.18. During the fourth phase (jump to the microcode exe¬ 
cution of the requested opcode) and during the final phase (jump 
to the microcode implementing the initial fetch cycle), inside the 
data bus nothing happens. 



To stop the operation of the described circuit, there is the stop in¬ 
struction (11111111 2 ), which stops the clock signal. The figure be¬ 
low shows this situation. 






































































































































































462 


A simple 8-bit CPU: version "A" 


Figure 9.19. The data bus when the instruction stop is exe¬ 
cuted: the control line CON 35 is activated, which then blocks the 
clock signal. To resume execution from that point, overcoming 
the stop, the switch located near the LED that is active should be 
turn on and off again. 



There should be available two videos that demonstrate the execution 
of only two instructions (macroinstructions): 


1. not_operate 

2. stop 

The first video ogv http://www.youtube.com/watch?v=8MahVvy 
BUOo shows what happens in the data bus, whereas the second 
one shows what happens inside the control unit ogv http://www. 
youtube.com/watch?v=pPxCQz7IFbM . 

To describe the content of the memory banks, including the RAM, a 








































































































































































A simple 8-bit CPU: version "A" 


463 


source file is used. The source file is written according to the syntax 
suitable for TKGate 2 (gmac precisely). The first directives describe 
the memory banks, which are organized this way: ctrl.mO is the first 
memory bank at the top of the control unit, ctrl.ml and ctrl.m2 are 
the two memories that contain the microcode, which are located at 
the bottom of the diagram of the control unit, ram.m3 is instead 
contained in the RAM module of the data bus and it contains the 
macrocode that initially is limited only to not_operate and stop. 


map 

bank[7:0] 

Ctrl.mO; 

microcode 

bank[31:0] 

ctrl.ml; 

microcode 

bank[35:32] 

Ctrl.m2; 

macrocode 

bank[7:0] 

ram.m3; 




464 


A simple 8-bit CPU: version "A" 


Figure 9.21. Where are located the memory banks. 



The source file then continues with the fields that divide each mi¬ 
crocode word (the memory cell used to represent a single microin¬ 
struction, made of ctrl.ml and ctrl.m2 joined together). For exam¬ 
ple, the least significant bit is called ctrl_start , while the most sig¬ 
nificant is called stop. It should be noticed that not all the 36 bit of 
the microcode word are described, because at the moment the code 
is limited to represent the reduction of the CPU in its first version. 


field 

ctrl_start [0]; 

// start from address 0 

field 

ctrl_load[1]; 

// load inside the counter 

field 

pc_br [ 2]; 

// PC <— bus 

field 

pc_bw[3]; 

// PC —> bus 

field 

pc_Inc [ 4]; 

// PC++ 































































A simple 8-bit CPU: version "A" 


465 


field mdr_br[9]; 
field mdr_bw[10]; 
field mar_br[ll]; 
field mar_bw[12]; 
field ram_br[13]; 
field ram_bw[14]; 
field ir_br[15]; 
field ir_bw[16]; 
field stop [ 35]; 


// MDR < — bus 
// MDR —> bus 
// MAR < — bus 
// MAR —> bus 
// RAM [mar] <— bus 
// RAM [mar] —> bus 
// IR <— bus 
// IR —> bus 
// stop clock 


The source file then describes the types of operands that the macroin¬ 
structions may have. It is expected to manage instructions without 
operands, or with only a single 8-bit operand. The meaning of the 
syntax used to describe the type op_0 and the type op_l should be 
intuitive: the former means no argument, while the latter means the 
presence of a single numeric 8-bit argument. 

operands op_0 { 

// 

// [ . ] 

// 

- = { }; 

}; 

operands op_l { 

// 

// [ . ] [nnnnnnnn ] 

// 

#1 = { +1=#1 [7:0] ; }; 

}; 







466 


A simple 8-bit CPU: version "A" 


There are then the opcode descriptions. For example, the instruction 
not_operate is equal to the zero opcode (OOOOOOOO 2 ), while the 
jump instruction has the opcode 15 (00001111 2 ). It should be noticed 
that in the first case (not_operate) there are no arguments, while 
in the second one an argument is required. 

op not_operate { 

map not_operate : 0; 

+ 0 [ 7 : 0 ]= 0 ; 
operands op_0; 

}; 

op jump { 

map jump : 15; // jump to #nn 

+0[7:0]=15; 
operands op_l; 

}; 

op stop { 

map stop : 255; // stop 

+0[7:0]=255; 
operands op_0; 

}; 


Then begins the microcode definition, which is placed starting from 
the first microcode word (address zero of the pair of memories 
ctrl.ml and ctrLm2). It begins from the description of the fetch and 
it ends with a jump to the microcode associated to the loaded op¬ 
code. Then, at the end of the description of each opcode (in the form 
of microcode), it is required to jump back to the first microinstruc¬ 
tion, which repeats the fetching cycle. 

begin microcode @ 0 




A simple 8-bit CPU: version "A" 


467 


// 

fetch: 

mar_br pc_bw; 
pc_Inc; 
ir_br ram_bw; 
ctrl_load; 

not_operate: 

ctrl_start ctrl_load; 

// 

jump: 

mar_br pc_bw; 
pc_br ram_bw; 
ctrl_start ctrl_load; 

// 

stop: 

stop; 

// If the clock signal is 
// resumed manually: 

ctrl_start ctrl_load; 

// 

end 


// MAR <— PC 
// PC++ 

// IR <— RAM [MAR] 

// jump to the 
// microcode implementing 
// the loaded opcode 

// jump to a new fetch 

// MAR <— PC 
// PC <— RAM [MAR] 

// jump to a new fetch 

// stop clock 

// jump to a new fetch 



468 


A simple 8-bit CPU: version "A" 


Figure 9.26. Match between the contents of the memory that rep¬ 
resents the microcode (the couple of memory banks m l and m2 
inside the control unit) and the microcode description itself. 


\% 




. *. \v 

\\ . \3 


^ . o. 

A A/ Si 


af 3/ 


\ rr// 


r ? / />' 



Finally, it starts the macrocode, or assembler code, which should be 
placed inside the RAM memory: 

begin macrocode @ 0 
start: 

not_operate 

stop 

end 



































































































































































A simple 8-bit CPU: version "A" 


469 


Figure 9.28. Macrocode contained inside the RAM memory. The 
memory cells marked with “xx” have an unspecified and un¬ 
known value. 



OF 

IF 


XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


Table 9.29. Macroinstructions list for this first stage of the CPU 
development. 


Syntax 

Description 

not_operate 

Do nothing, just go to the next instruction. 

jump #ref 

Jump to the instruction that is located at the 
specified address in memory. 

stop 

Stop the clock. 


The source file described above should be available at attachments/ 
xcpu/xcpu-al.gm . It follows the procedure to compile th source file 
with gmac20, the TKGate 2 code compiler: 

$ gmac20 -o x.mem -m x.map » 

^ xcpu-al. gm [ Enter ] 

The compilation produces the file ‘x.mem’ that contains the images 



















































470 A simple 8-bit CPU: version "A" 

for all the memory banks. It is a text file and it looks like this: 


^memory Ctrl.ml 
@0 

808 10 cOOO 2 3 808 4004 3 
0 3 

Omemory Ctrl.m2 
@0 

00000000 
8 0 

^memory ctrl.mO 

@0 

4 

@f 

5 

Off 

8 

Omemory ram.m3 
@0 

0 ff 




A simple 8-bit CPU: version "A" 


471 


The compilation produces also the file ‘x. map’ that contains the mi¬ 
crocode and macrocode maps; that is, the addresses of known labels: 


Microcode 

Symbols 

(total=4): 


fetch 



00000000 

jump 



00000005 

not_operate 


00000004 

stop 



00000008 

Macrocode 

Symbols 

(total=l): 


Global 


Local 


start 



00000000 


The file ‘x. mem’, produced by the compilation, is used by TKGate 2 
to load the initial memory banks’ contents. But an additional script 
is necessary: 

module LM(); 
initial 
begin 

$readmemh ("x.mem"); 
end 

endmodule 


This is a simple module —called LM inside the TKGate Verilog 
netlist source— that should be placed somewhere, just to make it 
work at the beginning of the TKGate simulation. The script is re¬ 
sponsible to load the file ‘x. mem’ in the memory banks. 

The TKGate 2 Verilog netlist source should be available at 








472 


A simple 8-bit CPU: version "A" 


attachments/xcpu/xcpu-al.v and TKGate might be used to exper¬ 
iment with this CPU version using the following command: 

$ tkgate20 xcpu-al. v [Enter] 

This first CPU version has also another instruction, not yet experi¬ 
mented: jump. The jump is done with the following steps: 

1. MAR ^ PC 

2. PCRAM [MAR] 

That is: the MAR register receives a copy of the PC register, which 
contains the address following the jump opcode. At the MAR ad¬ 
dress, the memory contains (should contain) another address, which 
is copied back to the PC register (and no increment is applied to the 
PC register). 

The jump opcode precedes an argument: a number representing a 
memory address, which is the place where the PC register should 
point, so that the next instruction would be the one located at the 
new address position. When the argument is read, it is not sent to the 
IR register, because it is not an opcode. 

The following macrocode example shows an infinite loop. Please 
notice that the TKGate compiler transforms the string #start into 
the address matching the label start inside the RAM memory: as 
the label start appears at the first position, it matches to the address 
zero. 

begin macrocode @ 0 
start: 

not_operate 
jump #start 



A simple 8-bit CPU: version "A" 


473 


end 


stop 


Figure 9.34. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 



OF 

IF 


XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


As it is an infinite loop, the stop is never reached. The follow¬ 
ing figures show what happens on the data bus after the instruction 
not_operate is executed. 
















































474 


A simple 8-bit CPU: version "A" 


Figure 9.35. The jump opcode is loaded and the PC register is 
pointing to the address following it; the MAR register is loading 
the memory content at the address pointed by PC. 




















































































































































































A simple 8-bit CPU: version "A" 


475 


Figure 9.36. The PC register is loaded with the value contained 
in memory at the address pointed by the MAR register. 



There should be available a video showing the example above: ogv 
http://www.youtube.com/watch?v=Z8bT08WjYYc . 


9.2 Version 7\2": memory index 

The second CPU subversion adds only a special register, named I 
(index), which should contain a memory index. It should be used 
to read and write the RAM memory through an index that could be 
managed. The I register is made the same way as MDR , MAR and 

IR. 













































































































































































476 


A simple 8-bit CPU: version "A" 


Figure 9.37. Simple CPU version “A2”. 











































































































A simple 8-bit CPU: version "A" 


All 


Inside the code that describes the microcode word’s fields, the fol¬ 
lowing fields are added: they are used specifically to manage the I 
register: 


field 

i_br[29]; 

// I <— bus 

field 

i_bw[30]; 

// I —> bus 


Inside the opcode list there are new instructions and the same is for 
the microcode description: 





478 


A simple 8-bit CPU: version "A" 


}; 

op move_mdr_i { 
map move_mdr_i : 

ii; 

// move 

MDR to I 

+0[7:0]=11; 
operands op 0; 

}; 

op move_i_mdr { 
map move_i_mdr : 

12; 

// move 

I to MDR 

+0[7:0]= 12; 
operands op 0; 

}; 





begin microcode @ 0 



load_ref: 



mar_br pc_bw; 

// MAR 

< — PC 

pc_Inc; 

// PC++ 

// The RAM memory does not 

have a 

clock. 

// thus, it is not possible to do 

just 

// MAR <— RAM [MAR] 



i_b r r am_bw; 

// I <- 

— RAM [MAR] 

ma r_b r i_bw; 

// MAR 

<— I 

mdr_b r r am_bw; 

// MDR 

<— RAM [MAR] 

ctrl_start ctrl_load; 

// CNT 

< — 0 

// 



load_reg: 



ma r_b r i_bw; 

// MAR 

<— I 

mdr_b r r am_bw; 

// MDR 

<— RAM [MAR] 

ctrl_start ctrl_load; 

// CNT 

< — 0 




A simple 8-bit CPU: version "A" 


479 


// 

store_ref: 

mar_br pc_bw; 

// 

MAR < — PC 


o 

1 

H 

b 

O 

> • 

// 

PC++ 


i_b r r am_bw; 

// 

I < — RAM [MAR] 

ma r_b r i_bw; 

// 

MAR <— I 


r am_b r mdr_bw; 

// 

RAM [MAR] <— 

MDR 

ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

store_reg: 

ma r_b r i_bw; 

// 

MAR <— I 


r am_b r mdr_bw; 

// 

RAM [MAR] <— 

MDR 

ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

move_mdr_i: 

i_b r mdr_bw; 

// 

I <— MDR 


ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

move_i_mdr: 

mdr_br i_bw; 

// 

MDR <— I 


ctrl_start ctrl_load; 

// 

CNT <— 0 


end 






480 


A simple 8-bit CPU: version "A" 


Figure 9.41. Match between the contents of the memory that rep¬ 
resents the microcode (the couple of memory banks ml and m2 
inside the control unit) and the microcode description itself. 


load_ref: 


k i 


\% 


\% \'cr 


1 1 


\<f 


% \% A- A/ A ^ 

■A . \p is 1 ! k'/ -kt // 


\£ 1/ #/ &? # # 


-£ 4 ; A/ '$($' 


i 

b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 b!9 b!8 b!7 b!6 M5 b!4 b!3 b!2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 


\ ^ H i t f / / 


r Y r / / 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


load_reg: 


store_ref: 


store_reg: 


move mdr i: 


move i mdr: 


0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


Table 9.42. Macroinstructions added for this version of the sim¬ 


ple CPU. 


Syntax 

Description 

load_ref #ref 

Load reference: it loads the value con¬ 
tained in memory, at the specified address, 
into the MDR register. The I register loads 
the argument. 



























































































































































































































































A simple 8-bit CPU: version "A" 


481 


Syntax 

Description 

load_reg 

Load register: it loads inside the MDR reg¬ 
ister the value contained in memory, at the 
address pointed by the I register. 

store_ref %ref 

Store reference: it copies into the memory, 
at the address specified by the argument, 
the value contained inside the MDR regis¬ 
ter. The I register loads the argument. 

store_reg 

Store register: it copies into the memory, 
at the address pointed by the I register, the 
value contained inside the MDR register. 

move_mdr_i 

It copies the MDR register into the I reg¬ 
ister. 

move_i_mdr 

It copies the I register into the MDR reg¬ 
ister. 


9.2.1 Loading instructions 

As a first example, the following macrocode is proposed: 

begin macrocode @ 0 
start: 

load_ref #data_l 

move_mdr_i 

load_reg 

stop: 

stop 

data_l: 

.byte 3 

end 











482 


A simple 8-bit CPU: version "A" 


The address matching the label data_l is loaded into the MDR 
register (it is the address 5). Then, MDR is copied into I (it is the 
value 3). Then, the value contained in memory at the address pointed 
by I is copied to MDR. At the address 3 there is the instruction 
load_reg which has the opcode 2: that is, at the end the MDR 
register contains the value 2. The full source should he available at 
attachments/xcpu/xcpu-a2.gm . 


Figure 9.44. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 

load_ref 

#data_l 

re_mdr_i 

load_reg 
stop 



start: 


7 8 


A B C D 


00 

01 

05 

0B 

02 

FF 

03 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

10 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 






F0 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


OF 

IF 

FF 


0 1 2345 67 8 9ABCDEF 
















































A simple 8-bit CPU: version "A" 


483 


Figure 9.45. Data bus after the execution of the load example 
above. Video: ogv http://www.youtube.com/watch?v=AXUSrH 
49cF49w 



9.2.2 Storing instructions 

The following example shows the usage of the instructions 
store_ref and store_reg: 

begin macrocode @ 0 
start: 

load_ref #data_l 
store_ref #data_2 
move_mdr_i 
store_reg 

stop: 

stop 






















































































































































484 


A simple 8-bit CPU: version "A" 


data_l: 




. byte 

15 

data_2 : 




. byte 

0 

end 




The MDR loads the value contained in memory at the address 
matching the label data_l (it loads the value 15). Then, the MDR 
content is written in memory at the address represented by the label 
data_2 (the value 15 is written at the address 8, replacing the pre¬ 
vious 0). Then, the MDR is copied to I (the I register will get the 
value 15). Then, at the address pointed by /, the memory is written 
with the value contained inside MDR (the value 15 is written at the 
address 15). 




A simple 8-bit CPU: version "A" 


485 


Figure 9.47. RAM memory before the execution. 



FO 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


OF 

IF 

FF 




















































486 


A simple 8-bit CPU: version "A" 


Figure 9.48. RAM memory after the execution of the 
store_ref instruction. 

load_ref 

#data_l 

store_ref 
#data_2 

move_mdr_i 
store_reg 
-stop 



start: 


8 


A B C D 


00 

01 

07 

03 

08 

0B 

04 

FF 

OF 

OF 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

10 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 






F0 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

c 

D 

E 

F 


OF 

IF 

FF 




















































A simple 8-bit CPU: version "A" 


487 


Figure 9.49. RAM memory at the end. 



FO 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


OF 

IF 

FF 





















































488 


A simple 8-bit CPU: version "A" 


Figure 9.50. Data bus after the execution of the store example 
above. Video: ogv http://www.youtube.com/watch?v=lHxx3SR 
56hE56 



9.3 Version "A3": general purpose registers 

The third subversion of the simple CPU adds two registers, at the 
moment without any particular purpose: A and B. These registers 
are made in the same way as /, MDR , MAR and IR. 






















































































































































A simple 8-bit CPU: version "A" 


489 


Figure 9.51. Simple CPU version “A3”. 




































































































































490 


A simple 8-bit CPU: version "A" 


Inside the code that describes the microcode word’s fields, the fol¬ 
lowing fields are added: they are used specifically to manage the A 
and B registers: 


field a_br[17]; 

// A <— bus 

field a_bw[18]; 

// A —> bus 

field b_br[27] ; 

// B <— bus 

field b_bw[28]; 

// B —> bus 

Inside the opcode list there are new instructions and the same is for 
the microcode description: 


op move_mdr_a { 

map move_mdr_a : 5; 
+0[7:0]=5; 
operands op_0; 

}; 

op move_a_mdr { 

map move_a_mdr : 6; 

+ 0 [ 7 : 0 ]= 6 ; 
operands op_0; 

}; 

op move_mdr_b { 

map move_mdr_b : 7; 
+0[7:0]=7; 
operands op_0; 

}; 

op move_b_mdr { 

map move_b_mdr : 8; 
+ 0 [ 7 : 0 ]= 8 ; 
operands op_0; 


// move MDR to A 


// move A to MDR 


// move MDR to B 


// move B to MDR 




A simple 8-bit CPU: version "A" 


491 


}; 


begin microcode @ 0 

move_mdr_a: 

a_b r mdr_bw; 

// 

A <— MDR 

ctrl_start ctrl_load; 

// 

CNT < — 0 

// 

move_a_mdr: 

md r_b r a_b w; 

// 

MDR <— A 

ctrl_start ctrl_load; 

// 

CNT <— 0 

// 

move_mdr_b: 

b_b r mdr_bw; 

// 

B <— MDR 

ctrl_start ctrl_load; 

// 

CNT < — 0 

// 

move_b_mdr: 

md r_b r b_b w; 

// 

MDR <— B 

ctrl_start ctrl_load; 

// 

CNT <— 0 

end 






492 


A simple 8-bit CPU: version "A" 


Figure 9.55. Match between the contents of the memory that rep¬ 
resents the microcode (the couple of memory banks m l and m2 
inside the control unit) and the microcode description itself. 


\% 



£ 

■5 

-Q; 




\ s if t 


I/#/ ## 


£ < 
-o.i -o’/ 
Ji u; 


'O/ 


O ; 
.C ; 

O 1 ! 

Q.:' 


<*/ n o4(# 


\\\\ t i a / 


r r / />' 



v v 






VI 


Table 9.56. Macroinstructions added for this version of the sim¬ 


ple CPU. 


Syntax 

Description 

move_mdr_a 

It copies the MDR content into the A reg¬ 
ister. 

move_a_mdr 

It copies the A content into the MDR reg¬ 
ister. 

move_mdr_b 

It copies the MDR content into the B reg¬ 
ister. 

move_b_mdr 

It copies the B content into the MDR reg¬ 
ister. 


It follows a macrocode example where some data is loaded from 
memory and stored inside the A and B registers: 









































































































































































A simple 8-bit CPU: version "A" 


493 


begin macrocode @ 0 
start: 

load_ref #data_l 
move_mdr_a 
load_ref #data_2 
move mdr b 


stop: 


stop 

data_l: 

.byte 17 

data_2 : 

.byte 11 


end 


It loads into the MDR register the value 17 (located in memory at 
the address matching the label data_l) and then it copies the loaded 
value into the A register. Then it does the same with the value 11 
(located in memory at the address matching the label data_2) that 
is copied into the B register. The full source file should be available 
at attachments/xcpu/xcpu-a3.gm . 



494 


A simple 8-bit CPU: version "A" 


Figure 9.58. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 



OF 

IF 


FO 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 




















































A simple 8-bit CPU: version "A" 


495 


Figure 9.59. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=9qVsCKmxcdk 



At the moment, the simple CPU under development is not able to 
copy the content of a register to another one, without the media¬ 
tion of the MDR register. In other words, there is no move_a_b 
instruction and the intended action is obtained instead with two 
steps: move_a_mdr and then move_mdr_b. That is made to keep 
the project very simple as long as possible. 

9.4 Version "A4": ALU 

The fourth subversion of the simple CPU receives an ALU 
{arithmetic-logic unit), including the ability to shift and rotate bits, 
but at the moment there is no management of flags (there are no 














































































































































































































































496 

carry, sign, zero and overflow flags). 


A simple 8-bit CPU: version "A" 



A simple 8-bit CPU: version "A" 


497 


Figure 9.60. Simple CPU version “A4”. 
















































































































































498 


A simple 8-bit CPU: version "A" 


Figure 9.61. The ALU structure: the red lines have an 8-bit size, 
while the black lines are single bit ones. 


> n ra 
L E cn r 
tc <d <d : 

O N C < 




^ _ 

CO CD <1> 


> o 
CO t 




00 

: D> - V 



<> 


. 00 

-£> - v 




f=0: NOT A (Carry and Overflow unchanged) 

f=1: A AND B (Carry and Overflow unchanged) 

f=2: A OR B (Carry and Overflow unchanged) 

f=3: A XOR B (Carry and Overflow unchanged) 

f=4: logic shift left 

f=5: logic shift right 

f=6: arithmetic shift left 

f=7: arithmetic shift right 

f=8: rotation left 

f=9: rotation right 

f=10: rotation left with carry 

f=11: rotation right with carry 

f=12: A plus B with carry 

f=13: A minus B with carry 

f=14: A plus B with no carry 

f=15: A minus B with no carry 








































































































































A simple 8-bit CPU: version "A" 


499 


Figure 9.62. Module shift, responsible to do bit shifts and bit 
rotations. 



v 

Co 


Y 

o 


M 

S 





















































500 


A simple 8-bit CPU: version "A" 


Figure 9.63. Module sh, contained inside the shift module, to 
shift the bits. 


rout 

right out A 


A>- 


0=logic shift 
1 =arithmetic shift 

la >- 

lr >- 


[4] 


nn 

v right in 


o 


[3] 




[3] 


0=left 

l=right 



[3] 




right 

side 

carry 


^ Cr 


[1] Arithmetic shift: 

- the shift should be arithmetic; 

- it should be a right shift; 

- the most significant bit should be L 

[2] Overflow: 

- the shift should be arithmetic; 

- the most significant bit should not 
have changed . 

[3] Connection to the most significant 
digit or to the sign . 

[4] Connection to the least significant digit 
[Cl] Left carry: 

- it should be a left shift; 

- the original most significant digit is L 
[Cr] Right carry: 

- it should be a right shift; 

- the original least significant digit is L 


€>%■ 


overflow 

> o 




left 

side 

carry 


Cl 


A left in 

lin 


v left out 

lout 
















































































































A simple 8-bit CPU: version "A" 


501 


Figure 9.64. Module as , which is able to add or subtract the in¬ 
puts. 


carry in 
borrow in 


f=0: S = A+B+Ci, Co contains the final carry if there is one 
f—l: S = A-B-Bi, Bo contains the final borrow, if there is one 



A > 


overflow 

fE>* 0 


carry out 
borrow out 


Co 








































































































502 


A simple 8-bit CPU: version "A' 


Inside the code that describes the microcode word’s fields, the fol¬ 
lowing fields are added: they are used specifically to manage the 
ALU. Please notice that the ALU has the ability to write to the bus, 
but it can not read directly from it, because the ALU does not re¬ 
ceive data from the bus; moreover, the ALU requires to control the 
function applied to the input data, 
field alu_f[22:19]={ 


not_a=0, 
a_and_b=l, 
a_or_b=2 , 
a_xor_b=3, 
logic_shift_left=4 , 
logic_shift_right=5, 
arith_shift_left=6, 
arith_shift_right=7, 
rotate_left = 8, 
rotate_right=9, 
rotate_carry_left=10, 
rotate_carry_right = l1, 
a_plus_b_carry=12, 
a_minus_b_borrow=13, 
a_plus_b=14 , 
a minus b=15 


}; 


field alu_bw[23]; 
field fl_ar[24] ; 


// ALU —> bus 
// FL <— ALU 


The field fl_ar can be ignored at the moment, because it will be use¬ 
ful only in the next subversion of the CPU, when the status flags will 



A simple 8-bit CPU: version "A" 


503 


be managed. Currently, inside the microcode, there are references 
to the field fl_ar , because in the next CPU subversion there will be 
the register FL , which currently is missing. There are many new 
opcodes for the ALU functions: 


op not { 

map not : 32; 

// A 

<— NOT A 

+0[7:0]=32; 
operands op 0; 

}; 

op and { 

map and : 33; 

// A 

<— A AND B 

+0[7:0]=33; 
operands op_0; 

}; 

op or { 

map or : 34; 

// A 

< — A OR B 

+0[7:0]=34; 
operands op_0; 

}; 

op xor { 

map xor : 35; 

// A 

< — A OR B 

+0[7:0]=35; 
operands op_0; 

}; 

op lshl { 

map lshl : 36; 

// A 

< — A « 1 

+0[7:0]=36; 
operands op_0; 

}; 

op lshr { 





504 


A simple 8-bit CPU: version "A" 




A simple 8-bit CPU: version "A" 


505 



begin microcode @ 0 
not: 

a_br alu_f=not_a alu_bw fl_ar; 
ctrl_start ctrl_load; 

// 

and: 

a_br alu_f=a_and_b alu_bw fl_ar; 
ctrl_start ctrl_load; 

// 

or: 

a_br alu_f=a_or_b alu_bw fl_ar; 
ctrl_start ctrl_load; 

// 

xor: 

a_br alu_f=a_xor_b alu_bw fl_ar; 
ctrl_start ctrl_load; 

// 

lshl: 

a_br alu_f=logic_shift_left alu_ 
ctrl_start ctrl_load; // CNT < — 0 

// 

lshr: 

a_br alu_f=logic_shift_right alu_bw fl_ar; // A <— A » 1 
ctrl_start ctrl_load; // CNT <— 0 

// 

ashl: 

a_br alu_f=arith_shift_left alu_bw fl_ar; // A < — A*2 
ctrl_start ctrl_load; // CNT <— 0 


// A <— NOT A 
// CNT <— 0 


// A <— A AND B 
// CNT <— 0 


// A <— A OR B 
// CNT <— 0 


// A <— A XOR B 
// CNT <— 0 


"KtaT -FI ^ T • // a — a 7 




506 


A simple 8-bit CPU: version "A" 


// 

ashr: 

a_br alu_f=arith_shift_right alu_bw fl_ar; // A <— A/2 
ctrl_start ctrl_load; // CNT <— 0 

// 

rot 1: 

a_br alu_f=rotate_left alu_bw fl_ar; // A <— A rot. left 
ctrl_start ctrl_load; // CNT <— 0 

// 


rotr: 

a_br alu_f=rotate_right alu_bw fl_ar; 
ctrl_start ctrl_load; 

// 


// A <— A rot. right 
// CNT <— 0 


add: 


// 


a_br alu_f=a_plus_b alu_bw fl_ar; 
ctrl_start ctrl_load; 


// A <— A + B 
// CNT <— 0 


sub: 


a_br alu_f=a_minus_b alu_bw fl_ar; 
ctrl_start ctrl_load; 


// A <— A - B 
// CNT <— 0 


end 



A simple 8-bit CPU: version "A" 


507 


Figure 9.68. Match between the contents of the memory that rep¬ 
resents the microcode (the couple of memory banks m l and m2 
inside the control unit) and the microcode description itself. 


I'O 


■■■-* \f -°j 

'•\^r O’ ^1 < 

Q . -Q: / 

/ of *>// 


yk \ 


\ i t t 


/ 




S -Q,/ <57 

3 <// 

, w CU ■ cry: ^, 

\£ \s e/ <?/ <$/ <? 


* i O/ ^. 
*>" */*/ 


X X H i M / / 


-£/ O/ / >P/* 3V 

O of C,/- 
Q./ Q./ Q. Cr/ 


r ^ a />" 


b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 bl9 bl8 bl7 bl6 bl5 bl4 bl3 bl2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 

not: 


and: 


or: 


xor: 


Ishl: 


Ishr: 


b22 b21 b20 bl9 bl8 bl7 bl6 bl5 bl4 bl3 bl2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 

- .V V 

0=not A \ \ 

1 =A and B \ ^ '\. 9 > 

2=A or B 

3=A xor B ^ ‘X 

4=A « 1 


b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 

y" 



0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

1 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

1 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

1 

0 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


5=A » 1 
6=A « 1 arith 
7=A » 1 arith 
8=A rot left 
9=A rot right 
A=A rot carry left 
B=A rot carry right 
C=A plus B carry 
D=A minus B borrow 
E=A plus B 
F=A minus B 







































































































































































































































508 


A simple 8-bit CPU: version "A" 




£ 


.. ■ 1 — 

o; < 

% 

\x3 \ 5 


o 

-o 

\± \ 

/ of 




<&/ 


/ 


■ . 

> „ \« \? 
% ^ \% 


\i 

\ 


il A 

CD / <D 

^ e e/ -c <$>/ 




O' <<$■/ 


\ Ml M 7 / 


o ; 

.C / 

O 1 ! 

CL! 




-o <$■ ^ " ^ 

a/ 


t 11 / / 



b35 

b34 

b33 

b32 

b31 

b30 

b29 

b28 

b27 

b26 

b25 

b24 

b23 

b22 

b21 

b20 

bl9 

bl8 

bl7 

bl6 

bl5 

bl4 

bl3 

bl2 

bll 

blO 

b9 

b8 

b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 

ashl: 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

1 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


ashr: 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

1 

1 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


rotl: 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

0 

0 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


rotr: 


add: 


sub: 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

1 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

b35 

b34 

b33 

b32 

b31 

b30 

b29 

b28 

b27 

b26 

b25 

b24 

b23 

b22 

b21 

b20 

bl9 

bl8 

bl7 

bl6 

bl5 

bl4 

bl3 

bl2 

bll 

bio 

b9 

b8 

b7 

b6 

b5 

b4 

b3 

b2 

bl 

bo 


V V 


s*>* 

<tf/ 


// 


0=not A 
1 =A and B 
2=A or B 
3=A xor B 
4=A « 1 


''?4% 


5=A » 1 
6=A « 1 arith 
7=A » 1 arith 
8=A rot left 
9=A rot right 
A=A rot carry left 
B=A rot carry right 
C=A plus B carry 
D=A minus B borrow 
E=A plus B 
F=A minus B 


Table 9.69. The new macroinstructions for the current CPU ver¬ 
sion. Some C and Verilog language notation is used to simplify 
the description. 


Syntax 

Description 

not 

A=~A 

One’s complement of A. 











































































































































































































































A simple 8-bit CPU: version "A" 


509 


Syntax 

Description 

and 

A =A ScB 

It is assigned to A the result of A AND B, 
bit per bit. 

or 

A =A \B 

It is assigned to A the result of A OR B, 
bit per bit. 

xor 

A = A A B 

It is assigned to A the result of A XOR B, 
bit per bit. 

lshl 

A = A « 1 

It is assigned to A the logic shift left of one 
bit from the previous value of A . 

lshr 

A = A » 1 

It is assigned to A the logic shift right of 
one bit from the previous value of A . 

ashl 

A = A «< 1 

It is assigned to A the arithmetic shift left 
of one bit from the previous value of A (it 
is the same as the logic shift left). 

ashr 

A = A »> 1 

It is assigned to A the arithmetic shift right 
of one bit from the previous value of A (the 
sign is kept the same). 

rot 1 

It is assigned to A the result of one bit ro¬ 
tation left from the original value of A . 

rotr 

It is assigned to A the result of one bit ro¬ 
tation right from the original value of A . 




510 


A simple 8-bit CPU: version "A" 


Syntax 

Description 

add 

A =A + B 

it is assigned to A the result of the sum of 
A and B, without considering the previous 
carry. 

sub 

A=A-B 

it is assigned to A the result of the subtrac¬ 
tion of A and B , without considering the 
previous borrow. 


The following sections offer various examples, where the use of all 
the new instructions is shown. 

9.4.1 Instruction "not" 


Listing 9.70. Macrocode example to experiment the not instruc¬ 
tion: a value is loaded from the memory to the A register, then 
the 1 ’ s complement is calculated and put into the A register. The 
complete source should be available at attachments/xcpu/xcpu- 
a4-not.gm . 


begin macrocode @ 0 
start: 

load_ref #data_l 

move_mdr_a 

not 

stop: 

stop 

data 1: 


end 


.byte 17 








A simple 8-bit CPU: version "A" 


511 


Figure 9.71. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 



OF 

IF 


FO 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 
















































512 


A simple 8-bit CPU: version "A" 


Figure 9.72. Data bus after the execution of the above ex¬ 
ample. Video: ogv http://www.youtube.com/watch?v=x5Vnhd 


72vh728 



9.4.2 Instruction "and" 

Listing 9.73. Macrocode example to experiment the and instruc¬ 
tion: two values are loaded from the memory into the registers A 
and B , then the binary AND is calculated and saved inside the A 
register. The complete source should be available at attachments/ 
xcpu/xcpu-a4-and.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move_mdr_a 
load_ref #data_2 





























































































































































































A simple 8-bit CPU: version "A" 


513 



move_mdr_b 


and 

stop: 

stop 

data_l: 

.byte 17 

data_2 : 

.byte 11 

end 



Figure 9.74. RAM memory content: the memory cells marked 
with “XX” have an unknown and unspecified value. 



XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


OF 

IF 

FF 






















































514 


A simple 8-bit CPU: version "A" 


Figure 9.75. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=2ra7SHxBvYY 



9.4.3 Instruction "or" 

Listing 9.76. Macrocode example to experiment the or instruc¬ 
tion: two values are loaded from the memory into the registers A 
and B , then the binary OR is calculated and saved inside the A 
register. The complete source should be available at attachments/ 
xcpu/xcpu-a4-or.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move_mdr_a 
load_ref #data_2 






































































































































































































A simple 8-bit CPU: version "A" 


515 



move_mdr_b 


or 

stop: 

stop 

data_l: 

.byte 17 

data_2 : 

.byte 11 

end 



Figure 9.77. RAM memory content: the memory cells marked 
with “XX” have an unknown and unspecified value. 



XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


OF 

IF 

FF 






















































516 


A simple 8-bit CPU: version "A" 


Figure 9.78. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=7E-2uA6fVoY 



9.4.4 Instruction "xor" 

Listing 9.79. Macrocode example to experiment the xor instruc¬ 
tion: two values are loaded from the memory into the registers A 
and B , then the binary XOR is calculated and saved inside the A 
register. The complete source should be available at attachments/ 
xcpu/xcpu-a4-xor.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move_mdr_a 
load_ref #data_2 
move mdr b 







































































































































































































A simple 8-bit CPU: version "A" 


517 



Figure 9.80. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 

load_ref 

#data_l 

mo ve_mdr_a 

load_ref 
#data_2 

mo ve_mdr_b 
xor 
^stop 



start: 


A B C D 


00 

01 

08 

05 

01 

09 

07 

23 

FF 

11 

0B 

XX 

XX 

XX 

XX 

XX 

XX 

10 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 






F0 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


OF 

IF 

FF 


0 1 2345 67 89ABCDEF 






















































518 


A simple 8-bit CPU: version "A" 


Figure 9.81. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=TuzknbyeabQ 



9.4.5 Instruction "Ishl" and "Ishr" 

Listing 9.82. Macrocode example to experiment the logic shift 
instructions: a value is loaded from the memory to the A register 
and a left shift is done, updating the value of A. Then the re¬ 
sult is copied into B , before another value is loaded to calculate 
the right shift. The complete source file should be available at 
attachments/xcpu/xcpu-a4-lsh.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move mdr a 






































































































































































































A simple 8-bit CPU: version "A" 


519 





520 


A simple 8-bit CPU: version "A" 


Figure 9.83. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 



OF 

IF 


XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 























































A simple 8-bit CPU: version "A" 


521 


Figure 9.84. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=pkRfWYqGeB4 



9.4.6 Instruction "ashl" and "ashr" 

Listing 9.85. Macrocode example to experiment the arithmetic 
shift instructions: a value is loaded from the memory to the A 
register and a left shift is done, updating the value of A . Then the 
result is copied into B , before another value is loaded to calculate 
the right shift. The complete source file should be available at 
attachments/xcpu/xcpu-a4-ash.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move mdr a 








































































































































































































522 


A simple 8-bit CPU: version "A' 





A simple 8-bit CPU: version "A" 


523 


Figure 9.86. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 



OF 

IF 


XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 























































524 


A simple 8-bit CPU: version "A" 


Figure 9.87. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=3rvRlWvWdlk 



9.4.7 Instruction "rotl" and "rotr" 

Listing 9.88. Macrocode example to experiment the rotation in¬ 
structions: a value is loaded from the memory to the A register 
and a left rotation is done, updating the value of A . Then the re¬ 
sult is copied into B , before another value is loaded to calculate 
the right rotation. The complete source file should be available at 
attachments/xcpu/xcpu-a4-rot.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move mdr a 






































































































































































































A simple 8-bit CPU: version "A" 


525 





526 


A simple 8-bit CPU: version "A" 


Figure 9.89. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 



OF 

IF 


XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 























































A simple 8-bit CPU: version "A" 


527 


Figure 9.90. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=KCi8n6bnLQo 



9.4.8 Instruction "add" 

Listing 9.91. Macrocode example to experiment the addition in¬ 
struction: two values are loaded from the memory into the reg¬ 
isters A and B , then the addition is calculated and saved in¬ 
side the A register. The complete source should be available at 
attachments/xcpu/xcpu-a4-add.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move_mdr_a 
load_ref #data_2 






































































































































































































528 


A simple 8-bit CPU: version "A" 



move_mdr_b 


add 

stop: 

stop 

data_l: 

.byte 17 

data_2 : 

.byte 11 

end 



Figure 9.92. RAM memory content: the memory cells marked 
with “XX” have an unknown and unspecified value. 



XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


OF 

IF 

FF 






















































A simple 8-bit CPU: version "A" 


529 


Figure 9.93. Data bus after the execution of the above 
example. Video: ogv http://www.youtube.com/watch?v=QQJ 
wz2yVwA8 



9.4.9 Instruction "sub" 

Listing 9.94. Macrocode example to experiment the subtraction 
instruction: two values are loaded from the memory into the reg¬ 
isters A and B , then the subtraction (. A-B ) is calculated and 
saved inside the A register. The complete source should be avail¬ 
able at a ttachments/xcpu/xcpu-a4-sub.gm . 
begin macrocode @ 0 
start: 

load_ref #data_l 
move_mdr_a 
load_ref #data_2 







































































































































































































530 


A simple 8-bit CPU: version "A" 



move_mdr_b 


sub 

stop: 

stop 

data_l: 

.byte 17 

data_2 : 

.byte 11 

end 



Figure 9.95. RAM memory content: the memory cells marked 
with “XX” have an unknown and unspecified value. 



XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 


OF 

IF 

FF 






















































A simple 8-bit CPU: version "A" 


531 


Figure 9.96. Data bus after the execution of the above example. 
Video: ogv http://www.youtube. com/watch ?v=VRd8ilJbK_ Y 



9.5 Version "A5": flags 

The fifth subversion of the simple CPU has a new special register: 
FL, used to store the status flags. With the FL register the ALU can 
use the previous carry (or borrow) for calculations and for rotations. 








































































































































































































532 


A simple 8-bit CPU: version "A" 


Figure 9.97. The simple CPU version “A5”. 


































































































































A simple 8-bit CPU: version "A" 


533 


The FL register can communicate with the bus, but it has an addi¬ 
tional input, Fi, which receives the updated status from the ALU. On 
the other hand, the output Fo sends to the ALU the current status of 
flags. The control input ar (ALU read ) is used to let the FL register 
load its value from the ALU. 



534 


A simple 8-bit CPU: version "A" 


Figure 9.98. Internal structure of the FL register: the eight 
aligned modules are D flip-flops. The diagram on the right is a 
compact version of the same circuit. 



-<Fi 































































































































A simple 8-bit CPU: version "A" 


535 


Inside the code that describes the microcode word’s fields, the fol¬ 
lowing fields are added, except fl_ar that already appeared in previ¬ 
ous version. The new fields are used specifically to manage the FL 
register: 


field fl_ar[24]; 

field fl_br[25]; 
field fl_bw[26]; 

// FL <— ALU 
// FL <— bus 
// FL —> bus 


Inside the opcode list there are new instructions and the same is for 
the microcode description: 


op move_mdr_fl { 

map move_mdr_fl : 9; 

+ 0 [ 7 : 0 ] = 9; 
operands op_0; 

}; 

op move_fl_mdr { 

// move MDR to FL 


map move_fl_mdr : 10; // move FL to MDR 
+ 0 [ 7 : 0 ]= 10 ; 
operands op_0; 

}; 


op rotcl { 

map rotcl : 42; 

+0[7:0]=42; 
operands op 0; 

}; 

op rotcr { 

map rotcr : 43; 

+0[7:0]=43; 
operands op 0; 

}; 

// A = A rotate carry left 

// A = A rotate carry right 




536 


A simple 8-bit CPU: version "A" 


op add_carry { 


map add_carry : 44; 

// A = A + B + carry 

+0[7:0]=44; 


operands op_0; 


}; 


op sub_borrow { 


map sub_borrow : 45; 

// A = A - B - borrow 

+ 0 [7:0]=4 5; 


operands op 0; 

}; 



begin microcode @ 0 


// 


move_mdr_f1: 

fl_br mdr_bw; 
ctrl_start ctrl_load; 

// 

move_fl_mdr: 

mdr_br fl_bw; 
ctrl_start ctrl_load; 

// 


// FL <— MDR 
// CNT <— 0 


// MDR <— FL 
// CNT <— 0 


rotcl: 

a_br alu_f=rotate_carry_left alu_bw fl_ar; // A <— A rot. carry 1 
ctrl_start ctrl_load; // CNT <— 0 

// 

rotcr: 

a_br alu_f=rotate_carry_right alu_bw fl_ar; // A <— A rot. carry r 
ctrl_start ctrl_load; // CNT <— 0 

// 


add_carry: 

a_br alu_f=a_plus_b_carry alu_bw fl_ar; // A <— A + B + carry 
ctrl_start ctrl_load; // CNT <— 0 

// 


sub_borrow: 

a_br alu_f=a_minus_b_borrow alu_bw fl_ar; // A <— A — B — borrow 




A simple 8-bit CPU: version "A" 


537 


ctrl_start ctrl_load; 

// CNT <— 

- 0 

end 




Figure 9.102. Match between the contents of the memory that 
represents the microcode (the couple of memory banks ml and 
m2 inside the control unit) and the microcode description itself. 


£ 

-Q; 


\% 


<?/ 

'Q/ <$./ 


£ < 
-Q. / -O / 


...... -H/ <>/ ^ 


2! # 


A/ 


&U Hi £/ wW a? <?/ 


ii r it // 


\Mi M a/ 


r i t />"' 



b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 b!9 bl8 b!7 bl6 bl5 b!4 b!3 bl2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 


/ .V \ 

0=not A \ \ 

1 =A and B \$> \<? 

V 2=A or B \<S 

3=A xor B ^ *’••• 

4=A « 1 

5=A » 1 

6=A « 1 arith 

7=A » 1 arith 

8=A rot left 

9=A rot right 

A=A rot carry left 

B=A rot carry right 

C=A plus B carry 

D=A minus B borrow 

E=A plus B 

F=A minus B 





















































































































































































































































538 


A simple 8-bit CPU: version "A" 


Table 9.103. Macroinstructions added for this version of the sim¬ 


ple CPU. 


Syntax 

Description 

move_mdr_f1 

It copies the MDR content into the FL reg¬ 
ister. 

move_fl_mdr 

It copies the FL content into the MDR reg¬ 
ister. 

rotcl 

It does a binary left rotation of the A reg¬ 
ister, using also the carry flag: the previ¬ 
ous carry shifts in, on the right, and the 
most significant bit is shifted out to the new 
carry value. 

rotor 

It does a binary right rotation of the A reg¬ 
ister, using also the carry flag: the previous 
carry shifts in, on the left, and the least sig¬ 
nificant bit is shifted out to the new carry 
value. 

add_carry 

It adds A and B and the previous carry, up¬ 
dating the A register and the new carry sta¬ 
tus. 

sub_borrow 

It subtracts A and B and the previous bor¬ 
row, updating the A register and the new 
borrow status (carry and borrow are the 
same flag). 


The following sections offer various examples, where the use of all 
the new instructions is shown. 




539 


A simple 8-bit CPU: version "A" 

9.5.1 Instruction "rotcl" and "rotcr" 


Listing 9.104. Macrocode example to experiment the rotation 
with carry: a value is loaded from the memory to the A regis¬ 
ter and a left rotation with carry is done five times, updating the 
value of A . Then the result is copied into B , before another value 
is loaded and rotated five times right. The complete source file 
should be available at a ttachments/xcpu/xcpu-a5-rotc.gm . 


begin macrocode @ 0 
start: 

load_ref #data_l 

move_mdr_a 

rotcl 

rotcl 

rotcl 

rotcl 

rotcl 

move_a_mdr 

move_mdr_b 

rotcr 

rotcr 

rotcr 

rotcr 

rotcr 


stop: 

stop 

data 1: 


end 


.byte 160 



540 


A simple 8-bit CPU: version "A" 


Figure 9.105. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. 



F0 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


XX 


OF 

IF 

FF 


0 1 234567 89ABCDEF 



















































A simple 8-bit CPU: version "A" 


541 


Figure 9.106. Data bus after the execution of the above example. 
Video: ogv http://www.youtube. com/watch ?v=Z13d- Tg5Cl Q 



9.5.2 Instruction "add_carry" 

Listing 9.107. Macrocode example to experiment the addition 
with carry: two 16-bit numbers should be added, splitting them 
and adding in two steps. The numbers are 12 FFi 6 and 11 EEi 6 . 
First there is the sum of FFi 6 and EEi 6 , without considering the 
previous carry, then there is the sum of 12 i6 and 11 i6 with the pre¬ 
vious carry. The result is EDi 6 plus a carry the first time, where 
the second time the result is 24 i6 . Every partial addition is saved 
in memory, so that at the address matching the label data_4 a 
16-bit result, little-endian, can be read. The complete source file 
should be available at attachments/xcpu/xcpu-a5-addc.gm . 
begin macrocode @ 0 
start: 



























































































































































































542 


A simple 8-bit CPU: version "A" 


stop: 

load_ref #data_0 

move_mdr_a 

load_ref #data_2 

move_mdr_b 

add 

move_a_mdr 

store_ref #data_4 
load_ref #data_l 

move_mdr_a 

load_ref #data_3 

move_mdr_b 

add_carry 

move_a_mdr 

store_ref #data_5 

stop 


// Oxl2FF = 4863 


data_0 : 

.byte OxFF 

data_l: 

.byte 0x12 


// OxllEE = 4590 


data_2 : 


data_3: 

.byte OxEE 

data_4 : 

.byte 0x11 

.byte 0 

data_5: 




A simple 8-bit CPU: version "A" 


543 





544 


A simple 8-bit CPU: version "A" 


Figure 9.108. RAM memory content before the program execu¬ 
tion: the memory cells marked with “xx” have an unknown and 
unspecified value. 












































A simple 8-bit CPU: version "A" 


545 


Figure 9.109. At the end of the macroprogram, the result is stored 
in memory. 



0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

c 

D 

E 

F 

00 

01 

15 

05 

01 

17 

07 

2E 

06 

03 

19 

01 

16 

05 

01 

18 

07 

10 

2C 

06 

03 

1A 

FF 

FF 

12 

EE 

ii 

ED 

_ k 

XX 

XX 

XX 

XX 

XX 


data_4: 
data 5: 


OF 

IF 


Figure 9.110. Data bus after the execution of the above 
example. Video: ogv http://www.youtube.com/watch?v= 
1 Xu4Mx WBwW4 





















































































































































































































546 

9.5.3 Instruction "sub borrow" 


A simple 8-bit CPU: version "A" 


Listing 9.111. Macrocode example to experiment the subtraction 
with borrow: the subtraction 12 EEi 6 -11FFi 6 is to be calculated. 
First a normal subtraction EEi 6 -FFi6 is done, saving the borrow 
request for the next subtraction: 12 i 6 -1 li6 -borrow. The first sub¬ 
traction gives EFie with a borrow request; the second subtraction 
gives 00i 6 . Every partial subtraction is saved in memory, so that 
at the address matching the label data_4 a 16-bit result, little- 
endian, can be read. The complete source file should be available 
at attachments/xcpu/xcpu-a5-subb.gm . 
begin macrocode @ 0 
start: 

load_ref #data_0 

move_mdr_a 

load_ref #data_2 

move_mdr_b 

sub 

move_a_mdr 
store_ref #data_4 
load_ref #data_l 
move_mdr_a 
load_ref #data_3 
move_mdr_b 
sub_borrow 
move_a_mdr 
store_ref #data_5 

stop: 

stop 

// Oxl2EE = 4846 



A simple 8-bit CPU: version "A" 


547 


data_0 : 

. byte 

OxEE 

data_l: 

. byte 

0x12 

// OxlIFF = 4607 

data_2 : 

. byte 

OxFF 

data_3: 

. byte 

0x11 

data_4 : 

. byte 

0 

data_5: 

. byte 

0 

end 





548 


A simple 8-bit CPU: version "A" 


Figure 9.112. RAM memory content before the program execu¬ 
tion: the memory cells marked with “xx” have an unknown and 
unspecified value. 



OF 

IF 


sub borrow 













































A simple 8-bit CPU: version "A" 


549 


Figure 9.113. At the end of the macroprogram, the result is stored 
in memory. 



0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

c 

D 

E 

F 

00 

01 

15 

05 

01 

17 

07 

2F 

06 

03 

19 

01 

16 

05 

01 

18 

07 

10 

2D 

06 

03 

1A 

FF 

FF 

12 

EE 

ii 

EF 

00 

1 

XX 

XX 

XX 

XX 

XX 


data_4: 
data 5: 


OF 

IF 


Figure 9.114. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=ofPUzdIids8 















































































































































































































550 


A simple 8-bit CPU: version "A" 


9.6 Version "A6": branching 

In the sixth version of the simple CPU a new module is added, with 
the purpose to test conditions on the value of the status flags (the 
FL register). The condition evaluation results in the choice from the 
value of two registers: MDR if the condition is true, or PC other¬ 


wise. 


A simple 8-bit CPU: version "A" 


551 


Figure 9.115. Simple CPU version “A6”. 
























































































































































552 


A simple 8-bit CPU: version "A" 


The SEL module gets two values from input A and input B. From 
the input Fi it gets the flags status, as it is output from the FL reg¬ 
ister. From the input/ the module SEL receives the condition to be 
checked: if the condition is true and the input bw is asserted, the 
module writes to the bus the same value obtained from the A input, 
otherwise, if the condition results false, the module writes to the bus 
the same value obtained from the B input. 


Figure 9.116. Module SEL , internal structure. 


o 


t 

v 


/ 


/ 


Fi 

V 


A B 

V V 


f = 0: if carry 
3 f = 1: if not carry 
f = 2: if zero 
f = 3: if not zero 
f = 4: if negative 
f = 5: if not negative 
f = 6: if overflow 
f = 7: if not overflow 


/ 


bO = carry 
bl = zero 
b2 = negative 
b3 = overflow 


/ 


dec 


O 1— c\] CO 


Q. 


^ in co n 


=0 

d> 

=o 

O 

CD- 

O 

=D- 

O 


o 


8/ / 8 


r> 


v- 


- <bw 


Y 

bus 


Inside the code that describes the microcode word’s fields, the fol- 































































A simple 8-bit CPU: version "A" 553 

lowing fields are added. The new fields are used specifically to man¬ 
age the SEL module: 



Inside the opcode list there are new instructions and the same is for 
the microcode description: 

op jump_if_carry { 

map jump_if_carry : 16; // jump to #nn if carry==l 

+0[7:0]=16; 
operands op_l; 

}; 

op jump_if_not_carry { 

map jump_if_not_carry : 17; // jump to #nn if carry==0 

+0[7:0]=17; 
operands op_l; 

}; 

op jump_if_zero { 

map jump_if_zero : 18; // jump to #nn if zero==l 

+0[7:0]=18; 
operands op_l; 

}; 

op jump_if_not_zero { 




554 


A simple 8-bit CPU: version "A" 


map jump_if_not_zero : 19; 

// jump to #nn if zero==0 

+0[7:0]=19; 


operands op_l; 


} ' 


op jump_if_negative { 


map jump_if_negative : 20; 

// jump to #nn if negative==l 

+0[7:0]=20; 


operands op_l; 


} ' 


op jump_if_not_negative { 

map jump_if_not_negative : 21; 

// jump to #nn if negative==0 

+0[7:0]=21; 


operands op_l; 


} ' 


op jump_if_overflow { 

map jump_if_overflow : 22; 

// jump to #nn if overflow==l 

+ 0[7:0]=22; 


operands op_l; 


} ' 


op jump_if_not_overflow { 

map jump_if_not_overflow : 23; 

// jump to #nn if overflow==0 

+0[7:0]=23; 


operands op_l; 


}; 



begin microcode @ 0 


jump_if_carry: 

mar_br pc_bw; 

pc_Inc; 

mdr_br ram_bw; 

pc_br sel_f=if_carry sel_bw 

ctrl_start ctrl_load; 

// 

// MAR <— PC 
// PC++ 

// MDR <— RAM [mar] 

// PC = (carry ? MAR : PC) 

// CNT < — 0 

jump_if_not_carry: 

mar_br pc_bw; 

pc_Inc; 

// MAR <— PC 

// PC++ 




A simple 8-bit CPU: version "A" 


555 


mdr_br ram_bw; 

// 

MDR <— RAM [mar] 


pc_br sel_f=if_not_carry sel_bw 

// 

PC = (not_carry ? MAR 

: PC) 

ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

jump_if_zero: 

mar_br pc_bw; 

// 

MAR <— PC 


pc_Inc; 

// 

PC++ 


mdr_br ram_bw; 

// 

MDR < — RAM [mar] 


pc_br sel_f=if_zero sel_bw 

// 

PC = (zero ? MAR : PC) 


ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

jump_if_not_zero: 

mar_br pc_bw; 

// 

MAR <— PC 


pc_Inc; 

// 

PC++ 


mdr_br ram_bw; 

// 

MDR < — RAM [mar] 


pc_br sel_f=if_not_carry sel_bw 

// 

PC = (not_zero ? MAR : 

PC) 

ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

jump_if_negative: 

mar_br pc_bw; 

// 

MAR <— PC 


pc_Inc; 

// 

PC++ 


mdr_br ram_bw; 

// 

MDR <— RAM [mar] 


pc_br sel_f=if_negative sel_bw 

// 

PC = (negative ? MAR : 

PC) 

ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

jump_if_not_negat ive: 

mar_br pc_bw; 

// 

MAR <— PC 


pc_Inc; 

// 

PC++ 


mdr_br ram_bw; 

// 

MDR <— RAM [mar] 


pc_br sel_f=if_not_negative sel_bw 

// 

PC = (not_negative ? MAR : PC) 

ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

j ump_if_over f1ow: 

mar_br pc_bw; 

// 

MAR <— PC 


pc_Inc; 

// 

PC++ 


mdr_br ram_bw; 

// 

MDR < — RAM [mar] 


pc_br sel_f=if_overflow sel_bw 

// 

PC = (overflow ? MAR : 

PC) 

ctrl_start ctrl_load; 

// 

CNT < — 0 


// 

jump_if_not_overf low: 

mar_br pc_bw; 

// 

MAR < — PC 




556 


A simple 8-bit CPU: version "A" 


pc_Inc; 

// PC++ 

mdr_br ram_bw; 

// MDR <— RAM [mar] 

pc_br sel_f=if_not_overflow sel_bw 

// PC = (not_overflow ? MAR : PC) 

ctrl_start ctrl_loadd¬ 

// CNT <— 0 

end 



Figure 9.120. Match between the contents of the memory that 
represents the microcode (the couple of memory banks ml and 
m2 inside the control unit) and the microcode description itself. 


. o 
■-o 


vL \ 


* ^ 


k: 

j <$/ ^ >$/ <&/ 


^ i < 

F/ $u/ 




\>gk -a 

A3 


4 'ov 


o; 
c; 


1 


jump_if_carry: 


jump_if_not_carry: 


jump_if_zero: 


jump_if_not_zero: 


Witt/ / 


k; K <p/ 

O / Of 

Q./ Q./ P/ <J / 


\\ MM // 


r f / />" 


4 

<8v 


.M V V 

0=not A 
1 =A and B 
2=A or B 
3=A xor B 
4=A « 1 
5=A » 1 
6=A « 1 arith 
7=A » 1 arith 
8=A rot left 
9=A rot right 
A=A rot carry left 
B=A rot carry right 
C=A plus B carry 
D=A minus B borrow 
E=A plus B 
F=A minus B 


M 


k / 

0=if carry 

'Q/ 

1 =if not carry 

oS / 

2=if zero 

CO; 

3=if not zero 


4=if negative 

5=if not negative 
6=if overflow 

7=if not overflow 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

111 0 

0 

0 

0 

0 

0 

0 

0 

0 

rr 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

[0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

E 

0 

0 

0 

0 

m 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

T 

0 

0 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

1 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

1 

1 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 





























































































































































































A simple 8-bit CPU: version "A" 


557 


\-o 


$!§' 4 ? J $ 4 " 0"4 


A \a 

* f ■' 


^ ^ 

. -Q; 'Q / >q . 

,3 j; $&? 


^ <P/ *£■'" 

-Q/ >£/ Np/ V <3>* 


O / 
C; 


iU r/// 


\X Hi iff / 


t t r />" 


b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 bl9 b!8 bl7 bl6 bl5 bl4 b!3 bl2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 


jumpjfjiegative: 


jump_if_not_negative: 


jumpjf_overflow: 


jumpJf_not_overflow: 


b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 bl9 b!8 bl7 bl6 bl5 bl4 b!3 bl2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0| 1| 0 

0 

0 

0 

0 

0 

0 

0 

0| 1| 0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

T 

0 

0 

0 

0 

T 

0 

0 

0 

0 

0 

0 

0 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

0 

0 

0 

0 

0 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

IT 

0 

0 

0 

0 

0 

0 

0 

0 

. 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

T 

0 

0 

0 

0 

T 

0 

0 

0 

0 

0 

0 

0 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

0 

1 

0 

0 

0 

0 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

IT 

0 

0 

0 

0 

0 

0 

0 

0 

, 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

a 


0 

0 

0 

a 

|o 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

0 

0 

0 

T 

0 

T 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

IT 

0 

0 

0 

0 

0 

0 

0 

0 

oa 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 


0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

a 


0 

0 

0 

a 

|o 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

1 

1 

0 

0 

1 

■ 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

A 

Lo 



/ .V \ 

0=not A \ \ 

1 =A and B \$>\<? 

<*/ 2=A or B 

3=A xor B ^ • 

4=A « 1 

5=A » 1 

6=A « 1 arith 

7=A » 1 arith 

8=A rot left 

9=A rot right 

A=A rot carry left 

B=A rot carry right 

C=A plus B carry 

D=A minus B borrow 

E=A plus B 

F=A minus B 


! ./ 

^ / 0=if carry 

<q / 1=if not carry 

2=if zero 

°/ 3=if not zero 

4=if negative 
5=if not negative 
6=if overflow 
7=if not overflow 


Table 9.121. Macroinstructions added for this version of the sim¬ 


ple CPU. 


Syntax 

Description 

jump_if_carry $ref 

If the carry flag is true, it jumps to 
the specified address. 

jump_if_not_carry #ref 

If the carry flag is false, it jumps to 
the specified address. 























































































































































































































558 


A simple 8-bit CPU: version "A" 


Syntax 

Description 

jump_if_zero %ref 

If the zero flag is true, it jumps to 
the specified address. 

jump_if_not_zero %ref 

If the zero flag is false, it jumps to 
the specified address. 

jump_if_negat ive %ref 

If the negative flag is true, it jumps 
to the specified address. 

jump_if_not_negative %ref 

If the negative flag is false, it 
jumps to the specified address. 

jump_if_overflow #ref 

If the overflow flag is true, it jumps 
to the specified address. 

jump_if_not_overflow %ref 

If the overflow flag is false, it 
jumps to the specified address. 


Listing 9.122. Macrocode example to experiment the selection 
module: there is a cycle where a variable is incremented until it 
contains the result of a sum with another variable. The complete 
source file should be available at attachments/xcpu/xcpu-a6.gm . 

begin macrocode @ 0 
start: 

load_ref #constant_zero 

move_mdr_b 

load_ref #variable_x 

move_mdr_a 

add 

cycle: 

jump_if_zero #stop 
load_ref #variable_y 
move mdr a 












A simple 8-bit CPU: version "A" 


559 


load_ref #constant_one 

move_mdr_b 

add 

move_a_mdr 

store_ref #variable_y 
load_ref #variable_x 
move_mdr_a 

load_ref #constant_one 

move_mdr_b 

sub 

move_a_mdr 

store_ref #variable_x 
jump #cycle 

stop: 

stop 

constant_zero: 

.byte 0 
constant_one: 

.byte 1 
variable_x: 

.byte 3 
variable_y: 

.byte 7 


end 




560 


A simple 8-bit CPU: version "A" 


Figure 9.123. RAM memory content before the program execu¬ 
tion: the memory cells marked with “xx” have an unknown and 
unspecified value. At the end of the execution, the memory cell 
at the address 23 i6 represents variable_y and it contains the value 
0Ai6 (10io). 

































A simple 8-bit CPU: version "A" 


561 


































562 


A simple 8-bit CPU: version "A" 


Figure 9.124. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=hFoOoGf86tO 



9.7 Version "A7": stack 

In the seventh subversion of the simple CPU the SP register is added 
0 stack pointer). This new register is to be used as the pointer for 
the stack. The stack is used mainly to allow the call of subroutines, 
with instructions like call and return, and to save and restore the 
registers. 




























































































































































































A simple 8-bit CPU: version "A" 


563 


Figure 9.125. Simple CPU version “A7”. 



























































































































































564 


A simple 8-bit CPU: version "A" 


The SP register has two extra control inputs: Inc and Dec , which re¬ 
quires, respectively, the increment or decrement of the register con¬ 
tent. 



A simple 8-bit CPU: version "A" 


565 


Figure 9.126. Register SP. 



















































































































































566 


A simple 8-bit CPU: version "A" 


Inside the code that describes the microcode word’s fields, the fol¬ 
lowing fields are added. The new fields are used specifically to man¬ 
age the SP register: 


field 

sp_br[31] ; 

// SP <— bus 

field 

sp_bw[32 ] ; 

// SP —> bus 

field 

sp_Inc[33] ; 

// SP++ 

field 

sp_Dec[34 ] ; 

// SP— 


Inside the opcode list there are new instructions and the same is for 
the microcode description: 


op call_ref { 
map call_ref : 

24; 

// call #nn 

+0[7:0]=24; 
operands op 1; 

}; 

op call_reg { 
map call_reg : 

25; 

// call I 

+0[7:0]=25; 
operands op_0; 

}; 

op return { 

map return : 26 

• 

f 

// return 

+0[7:0]=26; 
operands op_0; 

}; 

op push_mdr { 
map push_mdr : 

27; 

// push MDR 

+0[7:0]=27; 
operands op_0; 






A simple 8-bit CPU: version "A" 


567 


}; 

op push_a { 

map push_a : 28; 

// push A 

+0[7:0]=28; 
operands op_0; 

}; 

op push_b { 

map push_b : 29; 

// push B 

+0[7:0]=29; 
operands op_0; 

}; 

op push_fl { 

map push_fl : 30; 

// push FL 

+0[7:0]=30; 
operands op 0; 

}; 

op push_i { 

map push_i : 31; 

// push I 

+0[7:0]=31; 
operands op 0; 

}; 

op pop_mdr { 

map pop_mdr : 48; 

// pop MDR 

+0[7:0]=48; 
operands op 0; 

}; 

op pop_a { 

map pop_a : 49; 

// pop A 

+ 

O 

• • 

o 

II 

> • 




568 


A simple 8-bit CPU: version "A" 



begin microcode @ 0 

call_ref: 

mar_br pc_bw; 
pc_Inc; 

mdr_b r r am_bw; 
sp_Dec; 
mar_br sp_bw; 
ram_br pc_bw; 
p c_b r md r_b w; 
ctrl_start ctrl_load; 


// MAR <— PC 
// PC++ 

// MDR <— RAM [mar] 
// SC— 

// MAR <— SP 
// RAM [mar] < — PC 
// PC <— MDR 
// CNT <— 0 




A simple 8-bit CPU: version "A" 


569 


// 

call_reg: 


sp_Dec; 

// 

l 

1 

mar_br sp_bw; 

// 

MAR <— SP 

ram_br pc_bw; 

// 

U 

1 

1 

V 

r -'i 

1 

pc_br i_bw; 

// 

PC <— I 

ctrl_start ctrl_load; 

// 

CNT <— 0 


// 

return: 

mar_br sp_bw; 
sp_Inc; 
pc_br ram_bw; 
ctrl_start ctrl_load; 

// 

push_mdr: 


// 

push_a: 


// 


// MAR <- 
// SP++; 
// PC <— 
// CNT <- 


- SP 

RAM [mar] 

- 0 


sp_Dec; 

// 

^0 

l 

1 

mar_br sp_bw; 

// 

MAR <— SP 

ram_br mdr_bw; 

// 

RAM [mar] <— MDR 

ctrl_start ctrl_load; 

// 

CNT <— 0 


sp_Dec; 

// 

^0 

l 

1 

mar_br sp_bw; 

// 

MAR <— SP 

r am_b r a_bw; 

// 

RAM [mar] <— A 

ctrl_start ctrl_load; 

// 

CNT <— 0 

i_b: 



sp_Dec; 

// 

1 

1 

mar_br sp_bw; 

// 

MAR <— SP 



570 


A simple 8-bit CPU: version "A" 



r am_b r b_bw; 


// 

RAM [mar] <— B 


ctrl_start ctrl_ 

_load; 

// 

CNT <— 0 

// 





push_f1: 





sp_Dec; 


// 

SP — 


mar_br sp_bw; 


// 

MAR <— SP 


r am_b r f l_bw; 


// 

RAM [mar] < — FL 


ctrl_start ctrl_ 

_load; 

// 

CNT <— 0 

// 





push_i: 





sp_Dec; 


// 

SP — 


mar_br sp_bw; 


// 

MAR <— SP 


r am_b r i_bw; 


// 

RAM [mar] <— I 


ctrl_start ctrl_ 

_load; 

// 

CNT <— 0 

// 





pop_ 

_mdr: 





mar_br sp_bw; 


// 

MAR <— SP 


sp_Inc; 


// 

SP++ 


mdr_b r r am_bw; 


// 

MDR <— RAM [mar] 


ctrl_start ctrl_ 

_load; 

// 

CNT <— 0 

// 





pop_ 

_a: 





mar_br sp_bw; 


// 

MAR <— SP 


sp_Inc; 


// 

SP++ 


a_b r r am_bw; 


// 

A <— RAM [mar] 


ctrl_start ctrl_ 

_load; 

// 

CNT <— 0 

// 





pop_ 

_b: 





mar_br sp_bw; 


// 

MAR <— SP 



A simple 8-bit CPU: version "A" 


571 


sp_Inc; 

// 

SP++ 

b_b r r am_bw; 

// 

B <— RAM [mar] 

ctrl_start ctrl_load; 

// 

CNT <— 0 

// 

pop_f 1: 

mar_br sp_bw; 

// 

MAR <— SP 

sp_Inc; 

// 

SP++ 

f l_b r r am_bw; 

// 

FL < — RAM [mar] 

ctrl_start ctrl_load; 

// 

CNT <— 0 

// 

pop_i: 

mar_br sp_bw; 

// 

MAR <— SP 

sp_Inc; 

// 

SP++ 

i_b r r am_bw; 

// 

I <— RAM [mar] 

ctrl_start ctrl_load; 

// 

CNT < — 0 

end 



572 


A simple 8 -bit CPU : version " A " 


Figure 9.130. Match between the contents of the memory that 
represents the microcode (the couple of memory banks ml and 
m2 inside the control unit) and the microcode description itself. 


call_reg: 


return: 


pushjnbr: 


"O 


'Tv 


\£ \ 


-Q: 


v S^/ 


\<* 


\% ^ 

\\ 


£ / < 
- 0 , 1 ^ ; 
•3 


*/ 


O ; 

c; 


M r M / / 


%% k 1/ #/ ## 


\ A \ i i i / / 


Jy S " 

g? #/">/•" 


r i / />•" 


b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 b!9 b!8 b!7 b!6 b!5 b!4 b!3 b!2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 



0 

0 



0 





0 





0 









1 



0 




1 

1 




0 

0 

0 

0 

0 

0 





0 



0 


0 

0 





0 


0 

0 

0 

0 

0 




0 

0 


0 

o o 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 


1 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 







0 














0 












0 

0 

0 

1 

0 

0 


0 



0 



0 


0 

0 






0 

0 

1 



0 





0 



0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 


0 

0 

0 

0 

0 

1 


0 

0 


0 

0 

0 

0 

0 


0 



0 



0 


0 

0 







0 

0 

1 

0 

0 


0 



0 

1 


0 

1 


0 

0 

0 

0 

0 





0 



0 


0 

0 







0 

0 

0 

0 

0 





0 

0 

1 


T 

0 

0 

0 

0 





0 





0 








0 

0 



0 





0 



0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 



0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 



0 

0 

0 

0 

0 

1 


0 

0 
























0 









1 


_0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 


0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 



0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

1 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 



0 

0 

0 

0 

0 

0 

0 

0 

0 



0 




0 

0 











0 

0 


1 












1 


0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 


T 

0 

0 

0 

0 





0 



0 


0 

0 







0 

0 

0 

0 

0 





0 

0 


0 


0 

0 

1 


0 





0 



0 


0 

0 






0 

0 

1 



0 





0 



0 



















0 




1 


0 

1 









_0 

1 

0 

1 




0 

0 

0 

0 

0 








0 



0 

0 


0 





0 

0 






0 


b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 b!9 b!8 b!7 b!6 b!5 b!4 b!3 b!2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 


f 4 


J>f o / 
S/ 

Q.' / 

CO'/ o! 

CO: 

vs 



vy 


A 

*t£ 


tf 


0=not A 
1 =A and B 
2=A or B 
3=A xor B 
4=A « 1 
5=A » 1 
6=A « 1 arith 
7=A » 1 arith 
8=A rot left 
9=A rot right 
A=A rot carry left 
B=A rot carry right 
C=A plus B carry 
D=A minus B borrow 
E=A plus B 
F=A minus B 


* 


\4 


-Q: 
co ; 


0=if carry 
1 =if not carry 
2=if zero 
3=if not zero 
4=if negative 
5=if not negative 
6=if overflow 
7=if not overflow 






























































































































































































A simple 8-bit CPU: version "A" 


573 


-Q; 


-o 


'ia vs js! o/ 

\ *z. 


^ ^/ 

-Q: •S-' 'O/ '<?.•' <®' 

: of «5>/ 


I \l a/ 4/ 4- s*/ 

Hi/ ¥S f 


\ ^ 


o / 

C : 




O ■ O': 


-v.. N P/\ fy' 

^ 


i 


Hi i if/ / 


X \ \\ iff / 


iff/ / 


b35 b34 b33 b32 b31 b30 b29 b28 b27 b26 b25 b24 b23 b22 b21 b20 b!9 b!8 b!7 b!6 b!5 b!4 b!3 b!2 bll blO b9 b8 b7 b6 b5 b4 b3 b2 bl bO 


push_a: 


pushjb: 


push _fl: 


push_i: 


f 1 

\ \ 

J>f o / 

S/ 

Q.V / 

CO'/ o! 
co: 






vy 


\% 


// 

¥ 


H 


0=not A 
1 =A and B 
2=A or B 
3=A xor B 
4=A « 1 
5=A » 1 
6=A « 1 arith 
7=A » 1 arith 
8=A rot left 
9=A rot right 
A=A rot carry left 
B=A rot carry right 
C=A plus B carry 
D=A minus B borrow 
E=A plus B 
F=A minus B 




•O/ 
Co / 


0=if carry 
1 =if not carry 
2=if zero 
3=if not zero 
4=if negative 
5=if not negative 
6=if overflow 
7=if not overflow 



1 

0 



0 


0 

0 

0 

0 

0 

0 


0 

0 


0 







0 







0 






0 


1 

0 

0 

0 




0 

0 


0 



0 

0 


0 

0 

0 

0 


1 


0 

0 


0 



0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


T 


0 

0 

0 

0 


0 


0 

0 


0 



0 



0 

0 

0 

0 


0 


0 

0 

0 

0 



0 

0 

0 

0 


0 

0 

1 

0 



0 

0 

0 

0 

0 

0 





0 





0 

0 

1 






0 













1 















1 





















0 



























1 

1 


T 


0 



0 







0 






0 

0 

0 

0 


0 



0 


0 



0 



0 




1 

0 





0 




0 








0 

0 


1 


0 

0 








0 




0 




0 


1 

0 

0 











1 

0 

0 










0 






0 


0 




0 

0 


0 



0 



0 

0 

0 

0 




0 

0 

0 

0 



0 

0 

1 

1 



1 


0 





















0 













0 


1 


0 

















0 


1 
















0 

1 

0 




0 

0 


0 



0 



0 

0 

0 

1 




0 

0 


0 



0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 

b35 

b34 

b33 

b32 

b31 

b30 

b29 

b28 

b27 

b26 

b25 

b24 

b23 

b22 

b21 

b20 

b!9 

b!8 

b!7 

b!6 

b!5 

b!4 

b!3 

b!2 

bll 

bio 

b9 

b8 

b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 























































































































































































574 


A simple 8-bit CPU: version "A" 


\% 

'.'O 


\ 


& 

\C ^ 

~o! 


•of $>/ 


■-,/ \ . \% \| 4/ A/ ^v 


O : 
C / 


a/ 


*o/ 

af 




i 


ii r r/// 


pop_mdr: 


pop_a: 


popjb: 


popjl: 


pop_i: 


W\ i iff/ 


t t / />" 


b35 

b34 

b33 

b32 

b31 

b30 

b29 

b28 

b27 

b26 

b25 

b24 

b23 

b22 

b21 

b20 

bl9 

00 

X 

bl7 

bl6 

bl5 

bl4 

bl3 

bl2 

bll 

bio 

b9 

b8 

b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 


0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 


0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 


0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

1 

0 

0 

0 


1 

0 

0 

0 

0 


0 

0 

0 



0 




0 

0 


0 



0 





0 

0 




0 

0 

0 




0 

0 





0 

1 

1 


Ik V 


q// 

cor/ 


O: 

c; 


& 


\cr> 

vO 

\U 


\<& 

■-o 


<*/ 

<F/ 


/ V V 

0=not A 
1 =A and B 
2=A or B 
3=A xor B 
4=A « 1 
5=A » 1 
6=A « 1 arith 
7=A » 1 arith 
8=A rot left 
9=A rot right 
A=A rot carry left 
B=A rot carry right 
C=A plus B carry 
D=A minus B borrow 
E=A plus B 
F=A minus B 


' 


\4 


-o/ 

Co / 


0=if carry 
1 =if not carry 
2=if zero 
3=if not zero 
4=if negative 
5=if not negative 
6=if overflow 
7=if not overflow 


0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 


0 

0 

0 

0 

0 


0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 


0 

0 


0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

1 

0 

0 


0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 





1 




0 



0 








0 


0 




1 













0 

1 



0 

0 


0 



0 



0 


0 

0 





0 

0 



0 

0 

0 





0 





0 



0 

0 


1 



0 

0 

0 



0 

0 

0 

0 



0 




1 


0 

0 

0 



0 


0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 


0 




0 

0 




1 

0 





0 

0 



0 


0 

0 



1 

0 

0 





0 



0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

0 

1 

1 


0 

0 

0 

1 


0 

0 

0 

0 



0 

0 

0 

0 


0 

0 

0 

0 


0 

0 

0 

1 



0 

0 

0 

0 



0 


0 

0 

0 

1 



0 

0 

0 

0 



0 

0 

0 

0 


0 

0 

0 

0 

0 

0 

0 

0 

0 


0 

0 

0 

0 

0 



0 


0 


0 

0 

0 

0 



0 


0 

0 


0 

0 


0 

0 


0 


1 



0 

0 

0 

1 



0 

0 

0 

0 


0 


0 

0 




0 

0 

0 

0 



0 



0 


0 

0 





0 

0 




0 

0 





0 

1 

_ 

1 

b35 

b34 

b33 

b32 

b31 

b30 

b29 

b28 

b27 

b26 

b25 

b24 

b23 

b22 

b21 

b20 

b!9 

b!8 

bl7 

bl6 

bl5 

bl4 

bl3 

bl2 

bll 

bio 

b9 

b8 

b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 





































































































































































































































A simple 8-bit CPU: version "A" 


575 


Table 9.131. Macroinstructions added for this version of the sim¬ 


ple CPU. 


Syntax 

Description 

call_ref #ref 

It decrements the value inside the SP reg¬ 
ister and saves in memory, at the new SP 
position, the address of the next instruction 
(after call_...), then it updates the PC reg¬ 
ister with the address specified (the argu¬ 
ment). That is: it calls the procedure stor¬ 
ing inside the stack the return address. 

call_reg 

It decrements the value inside the SP reg¬ 
ister and saves in memory, at the new SP 
position, the address of the next instruction 
(after call_ ....), then it updates the PC reg¬ 
ister with the address contained inside /. 
That is: it calls the procedure storing inside 
the stack the return address. 

return 

It increments the SP register and restores 
the register PC loading from memory the 
content at the address pointed by the up¬ 
dated SP. That is: it returns from a proce¬ 
dure call. 

push_mdr 

It saves on top of the stack the value of 

MDR. 

push_a 

It saves on top of the stack the value of A . 

push_b 

It saves on top of the stack the value of B. 

push_f1 

It saves on top of the stack the value of FL. 




576 


A simple 8-bit CPU: version "A" 


Syntax 

Description 

push_i 

It saves on top of the stack the value of /. 

pop_mdr 

It pops from the stack a value that is loaded 
by the MDR register. 

pop_a 

It pops from the stack a value that is loaded 
by the A register. 

pop_b 

It pops from the stack a value that is loaded 
by the B register. 

pop_f1 

It pops from the stack a value that is loaded 
by the FL register. 

pop_i 

It pops from the stack a value that is loaded 
by the I register. 


9.7.1 Instruction "push" and "pop" 

Listing 9.132. Macrocode example to experiment the instruction 
for adding and removing values from the stack: it is saved a value 
from the A register and then it is restored inside the B regis¬ 
ter. The complete source file should be available at attachments/ 
xcpu/xcpu-a7-push-pop.gm . 
begin macrocode @ 0 
start: 

load_ref #sp_bottom 

move_mdr_sp 

load_ref #data_0 

move_mdr_a 

push_a 

pop_b 












A simple 8-bit CPU: version "A" 577 


stop: 


stop 


sp_bottom: 


. byte 

0x10 

data_0 : 


. byte 

OxCC 

end 



Figure 9.133. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. The memory 
cell at the address 0Fi 6 is written by the instruction push_a. 



F0 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 

XX 


0 

1 

2 

3 

4 

5 

6 

7 

8 

9 

A 

B 

C 

D 

E 

F 













































578 


A simple 8-bit CPU: version "A" 


Figure 9.134. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=vAdVww31D7I 



9.7.2 Instruction "call" and "return" 

Listing 9.135. Macrocode example to experiment the instructions 
for calling a procedure and returning from a procedure. The com¬ 
plete source file should be available at attachments/xcpu/xcpu- 
a7-call-return.gm . 

begin macrocode @ 0 
start: 

load_ref #sp_bottom 
move_mdr_sp 
call_ref #elab 
move_a_mdr 
move mdr b 




































































































































































































































A simple 8-bit CPU: version "A" 579 





580 


A simple 8-bit CPU: version "A" 


Figure 9.136. RAM memory content: the memory cells marked 
with “xx” have an unknown and unspecified value. The memory 
cell at the address 1 Fi 6 is written by the instruction call_ref. 



































A simple 8-bit CPU: version "A" 


581 


Figure 9.137. Data bus after the execution of the above example. 
Video: ogv http://www.youtube.com/watch?v=nWdXMvegkjc 



9.8 Version "A8": I/O 


The previous subversion of the simple CPU is complete enough to 
show the main functions of a common CPU. This new subversion ex¬ 
tends the project introducing I/O devices. Two new busses are added, 
used for the data to move with devices and to select a specific device. 

9.8.1 Communication with asynchronous devices 

Usually, the I/O devices are not synchronous with the CPU clock, 
therefore it is necessary a protocol, so that it can be made a request 
of an action to the device and a feedback from the device can be 
received. The I/O devices used in this simple CPU project have ex¬ 
ternally the connections shown in the next figure. 

































































































































































































































582 


A simple 8-bit CPU: version "A" 


Figure 9.138. One input device and one output device. 


REQ 

-► 

REQ 

DATA keyboard 

-► 

DATA display 

ACK 

◄- 

ACK 

CLR 

-► 

CLR 


The input or output DATA allows to move the information that is 
needed by the device or that is generated from it. The inputs REQ 
(request) and ACK (acknowledge) are used to negotiate the informa¬ 
tion movement (the input CLR is used only to clear the device). Two 
examples should be done, to examine the procedure of reading from 
the device and of writing on it. 

To communicate with an input device, from which a data is to be 
read, it is required to activate the input REQ (tj) to request the data. 
The device receives the request and prepares the output DATA with 
the information (t 2 ), then it activates the output ACK (t 3 ). At that 
point, finding the output ACK active, it is possible to read from the 
output DATA (t 4 ) and after the read operation it is possible to disable 
the input REQ ( t 5 ). The device, finding the input REQ disabled, 
knows that the information was taken, then it stops to keep it ( t 6 ) 
and disables the output ACK (t 7 ). 












A simple 8-bit CPU: version "A" 


583 


Figure 9.139. Phases for reading an input device and for writing 
to an output device. 


REQ 

ACK 


read from the device 

t 0 ti t 2 t 3 t 4 t 5 t 6 t 7 


| valid data | 


write to the device 

7 


| valid data | 


t 0 t 2 t 3 t 4 t 5 t 6 t 


To communicate with an output device, where an information is to 
be written, it is necessary to prepare that data to the input DATA (, t 0 ), 
then it is necessary to activate the input REQ (ti) to tell the device 
that the data is ready. Then the device gets the information (t 2 ) and it 
confirms activating the output ACK (t 3 ). Finding the confirmation, it 
is not necessary to keep the information on the input DATA (t 4 ) and 
the input REQ is disabled (t 5 ). The device, finding that the request is 
completed, disables the output ACK (t 7 ) concluding the operation. 


9.8.2 I/O devices implementation 


At the moment, only two I/O devices are implemented: a keyboard 
and a screen. As the project is developed with TKGate, the devices 
are made through TCL/Tk code. The code that is shown was ob¬ 
tained modifying similar devices from the TKGate library. 












































584 


A simple 8-bit CPU: version "A" 


Listing 9.140. File ‘ share/tkgate/vpd/kbd. tel’ to simulate 
the keyboard input. The program shows a little empty window, 
which should be selected to type something that could be re¬ 
ceived by the related virtual device. 

VPD::register KBD 
VPD::allow KBD::post 

namespace eval KBD { 

# Public variables declaration. $kbd_w is an array that is 

# used only for the element $n. $kbd_w ($n) identifies uniquely 

# the working interface instance. 

variable kbd_w 
variable KD 

# Function required by TKGate to create the interface. 

proc post {n} { 

variable kbd_w 

# It creates a window and saves the object inside the array 

# $kbd_w. 

set kbd_w($n) [VPD::createWindow "KBD $n" -shutdowncommand "KBD::unpost $n"] 

# It links the keyboard typing, related to the object represented 

# Jby $kbd_w($n), to the sendChar function. 

bind $kbd_w($n) <KeyPress> "KBD::sendChar $n \"%A\"" 

# It opens a write channel, named "KD". 

if {[info exists ::tkgate_islnitialized]} { 

VPD::outsignal $n.KD KBD::KD($n) 

} 

} 

# Function that gets the typing and puts it into the channel 

# "KD”, related to the current interface instance. 

proc sendChar {n key} { 
variable KD 

if { [string length $key ] == 1 } { 

binary scan $key c c 
set KBD::KD($n) $c 

} 

} 

# Function required by TKGate to destroy the interface. 

proc unpost {n} { 
variable kbd_w 
destroy $kbd_w($n) 
unset kbd_w($n) 

} 

} 



A simple 8-bit CPU: version "A" 


585 


Listing 9.141. File ‘share/tkgate/vpd/scr. tel’ to simulate 
the output on a character screen. The program shows a window 
where the sent characters are shown. Inside the code there is a 
reference to the file ‘txteurs .b’ that is already included with 
the TKGate distribution. _ 

image create bitmap txteurs -file ”$bd/txtcurs.b" 

VPD::register SCR 
VPD::allow SCR::post 
VPD::allow SCR::data 

namespace eval SCR { 

# Public variables declaration: these are arrays where only 

# the element $n is used. The element $n identifies uniquely 

# the working interface instance. 

variable scr_w 
variable scr_pos 

# Function required by TKGate to create the interface. 

proc post {n} { 

variable scr_w 
variable scr_pos 

# It creates the window and it saves the object inside the array 

# $scr_w. 

set scr_w($n) [VPD::createWindow "SCR $n" -shutdowncommand "SCR::unpost $n"] 

# For convenience, it copies the object reference inside the local variable 

# $W and then the object is referred only with that variable. 

set w $scr_w($n) 

text $w.txt -state disabled 

pack $w.txt 

# It puts the cursor at the end of the shown text. 

$w.txt image create end -image txteurs 

# It opens a reading channel, called "RD" and it connects it to the 

# function "data”. 

if {[info exists ::tkgate_islnitialized]} { 

VPD::insignal $n.RD -command "SCR::data $n" -format %d 

} 

# It clears the counter for the shown characters on screen. 

set scr_pos($n) 0 

} 

# Function required by TKGate to destroy the interface. 

proc unpost {n} { 
variable scr_w 
destroy $scr_w($n) 




586 


A simple 8-bit CPU: version "A" 


unset scr_w($n) 

} 

# Function used for receiving the data to be shown on screen. 

proc data {n c} { 
variable scr_w 
variable scr_pos 

# For convenience, it copies the interface object reference inside 

# the local variable $w. 

set w $scr_w($n) 
catch { 

# The $c variable contains the character to be shown. 

if { $c == 7 } { 

# BEL 

bell 

return 

} elseif { $c == 127 | | $c == 8 } { 

# DEL I BS 

if { $scr_pos($n) > 0 } { 

# It deletes the last shown character, but only if the 

# characters counter is greater then zero, otherwise 

# the cursor would disappear and the newly received 

# characters could be placed inside an invisible area 

# of the virtual screen. 

$w.txt configure -state normal 
$w.txt delete "end - 3 chars" 

$w.txt see end 

$w.txt configure -state disabled 

set scr_pos ($n) [expr {$scr_pos($n) - 1}] 

} 

return 

} elseif {$c==13}{ 

# CR is translated into LF. 

set c 10 

} 

# It converts the character number into a symbol that can 

# be shown. 

set x [format %c $c] 

# It shows the symbol. 

$w.txt configure -state normal 
$w.txt insert "end - 2 chars" $x 
$w.txt see end 

$w.txt configure -state disabled 

# It updates the shown characters counter. 

set scr_pos($n) [expr {$scr_pos ($n) + 1}] 

} 

} 



A simple 8-bit CPU: version "A" 


587 


} 


The two TCL/Tk programs are called by some Verilog code. The 
following listings show the modules keyboard and display , which 
appear graphically as in the figure 9.138. 

Listing 9.142. Verilog code for the keyboard module. 

module keyboard (DATA, REQ, ACK, CLR); 

output ACK; 

output [7:0] DATA; 

input REQ; 

input CLR; 

reg ready; 

reg [7:0] key; 

initial 

begin 

ready = 0; 
key = 0; 
end 

always 

begin 

@ (posedge CLR) 
ready = 0; 
key = 0; 
end 

initial $tkg$post("KBD","%m"); 






588 


A simple 8-bit CPU: version "A' 



Listing 9.143. Verilog code for the display module. 

module display(DATA, REQ, ACK, CLR); 

output ACK; 

input [7:0] DATA; 

input REQ; 

input CLR; 

reg ready; 

initial 

begin 

ready = 0; 






A simple 8-bit CPU: version "A" 


589 



Until now, the described devices can work only asynchronously, but 
to be used, they must be adapted to work synchronously with the 





590 A simple 8-bit CPU: version "A" 

CPU. 

9.8.3 External appearance of the synchronous interfaces 


The synchronous interfaces for the I/O devices should be connected 
to the CPU data bus, just like the other modules already imple¬ 
mented. However, to simplify the connections, instead of having per¬ 
sonal control lines, an additional bus is created for the I/O module 
address to be selected. 

Figure 9.144. I/O modules connection. 


I/O devices control bus 



As the figure shows, the bus connected to the inputs ADDR is used to 
select the device, while the bus connected to the inputs CON is used 
to uniform the control lines for all the I/O modules. Please notice that 
























A simple 8-bit CPU: version "A" 


591 


the inputs CON are the same for all I/O modules, but every module 
uses only the lines that it requires, ignoring the others: 


CON 



0 

2 

3 


bus read 

bus write 
request 

is ack? 


The lines bus read and bus write are the same of the other modules 
already described and they refer to the request to read the CPU data 
bus or write to the CPU data bus. The line request is used to request a 
read or write operation on the device, but without the need to keep it 
active as it should for the asynchronous protocol already mentioned. 
The line is ack? is used to obtain, somehow, an acknowledgment 
from the device. 


9.8.4 Synchronous keyboard interface 

The keyboard interface module uses only two out of the four control 
lines: bus write and request. 








592 


A simple 8-bit CPU: version "A" 


Figure 9.146. Module KBD , which connects the keyboard to the 
CPU data bus. 



























































A simple 8-bit CPU: version "A" 


593 


To communicate with the keyboard module it is necessary to start 
with a request signal. Then, after a positive clock edge, the request 
is saved inside the upper JK flip-flop, which is activated. That flip- 
flop has the task to keep the request active on the input REQ of the 
device. The second central JK flip-flop has the task to save the ac¬ 
knowledge produced by the output ACK and, if that acknowledge 
is active inside the flip-flop, it does not allow to receive another re¬ 
quest. After a request is correctly received and saved, if the device 
has a character ready to be output, it replies almost immediately, 
placing that character on its DATA output and activating the output 
ACK. At the second positive clock edge, the flip-flop responsible for 
the request signal is cleared and instead is activated the second flip- 
flop responsible for the acknowledge. However, the device continue 
to keep its DATA with the character to be read. Then, a bus write 
signal is received, allowing to write the character (read from the de¬ 
vice) into the CPU data bus. This action clears also the acknowledge 
flip-flop. If otherwise, the keyboard device is not yet ready to offer 
a character, the interface will write to the CPU data bus a null value 
(00i 6 ), because the acknowledge flip-flop is not activated. 

At the macrocode level, if the keyboard read produces a null charac¬ 
ter, it just means that there is not a character ready and the keyboard 
read should be retried. 

9.8.5 Synchronous display interface 

The DSP module uses all the control lines, because it must be able 
to read from the CPU data bus when a character is to be shown on 
the screen, but must also be able to write to the bus to give the ac¬ 
knowledge of the work properly done. 


594 


A simple 8-bit CPU: version "A" 


Figure 9.147. Module DSP. 


data 





































































A simple 8-bit CPU: version "A" 


595 


The DSP module uses a register made out of eight D flip-flops (posi¬ 
tive edge triggered, module DR8 ) which is used to save the character 
to be shown on the screen. However, when the control line is ack? is 
active, the DSP module writes to the CPU data bus the result of its 
work: 00i 6 means that the last character to be displayed is not already 
appeared, whereas FF i6 means that the last character to be displayed 
was correctly shown. 



596 


A simple 8-bit CPU: version "A" 


Figure 9.148. Building DRn modules. 



Q 

To show a character on screen, it is necessary to start activating the 
control line bus read : after the next clock positive edge the inter¬ 
nal data register loads the character reading it from the CPU data 
bus, while the JK flip-flop in the middle is cleared and so is the ack 














































































A simple 8-bit CPU: version "A" 


597 


multiplexer, connected to the flip-flop output. Then the control line 
request should be activated: after the next clock positive edge this 
value is saved inside the JK flip-flop on the top side, activating the 
input REQ of the device. Then, after a while, the device shows the 
character that is already available at its DATA input (it comes from 
the data register) and then it replies activating its ACK output. When 
the ACK output from the device is active and a new clock positive 
edge comes, the JK flip-flop on the top is reset and the other JK 
flip-flop is activated, switching the connected multiplexer. 

To show a character, only two clock cycles are required, but to be 
able to verify if there is an acknowledge, it is necessary to read the 
device after it. To check the acknowledgement it is necessary to ac¬ 
tivate the control line is ack? and bus write , so that the interface can 
write to the bus the value 00 for a negative acknowledge, or FF for 
a positive acknowledge. 

9.8.6 The CPU data bus with the I/O interfaces 

Together with the I/O interface modules, also a new register is added: 
10A (I/O address). When a device is to be reached, it is necessary to 
load its I/O address into the IOA register, before anything else can 
be done with the device itself. 


598 


A simple 8-bit CPU: version "A" 


Figure 9.149. The CPU data bus with the IOA register and the 
I/O interfaces. 






































































































































































































599 


A simple 8-bit CPU: version "A" 

The CPU control bus is now modified with the addition of the lines 
used to control the IOA register and the I/O interfaces. That modifi¬ 
cation requires to shift the line used to stop the clock. Therefore, in¬ 
side the memory banks declaration code and inside the control word 
fields declaration code there are the following adaptations: 


map 

bank [7:0] 

Ctrl.mO; 

microcode bank [31:0] 

Ctrl.ml; 

microcode bank [ 41 : 32 ] 

Ctrl.m2; 

macrocode bank[7:0] 

ram.m3; 

field 

ioa_br[35] ; 

// IOA <— bus 

field 

ioa_bw[36] ; 

// IOA —> bus 

field 

io_br[37 ] ; 

// I/O <— bus 

field 

io_bw[38] ; 

// I/O —> bus 

field 

io_req[39] ; 

// I/O request 

field 

io_isack [40]; 

// I/O is ack? 

field 

stop[ 41 ]; 

// stop clock 


Inside the opcode list there are new instructions and the same is for 
the microcode description. There is also a new instruction that re¬ 
quires two arguments: 

operands op_2 { 

// 

// [ . ] [nrnmrnmrnmim ] [nnnnnnnn ] 

// 

# 1,#2 = { +1=#1 [7:0]; +2=#2[15:8]; }; 

}; 





600 


A simple 8-bit CPU: version "A" 


op in { 

map in : 48; // read input from I/O bus 

+0[7:0]=48; 
operands op_l; 

}; 

op out { 

map out : 49; // write output to I/O bus 

+0[7:0]=49; 
operands op_l; 

}; 

op io_is_ack { 

map io_is_ack : 50; 

+0[7:0]=50; 
operands op_2; 

}; 


begin microcode @ 0 

in: 

mar_br pc_bw; 

// 

MAR <— PC 

pc_Inc; 

// 

PC++ 

md r_b r r am_bw; 

// 

MDR <— RAM [mar] 

ioa_br mdr_bw; 

// 

IOA < — MDR 

io_req; 

// 


io_br; 

// 

does not do anything 

a_br io_bw; 

// 

A < — I/O 

ctrl_start ctrl_load; 

// 

CNT < — 0 

out: 

mar_br pc_bw; 

// 

MAR <— PC 

pc_Inc; 

// 

PC++ 




A simple 8-bit CPU: version "A" 


601 


md r_b r r am_bw ; 

// 

MDR <— 

RAM [mar] 

ioa_br mdr_bw; 

// 

IOA < — 

MDR 

io_br a_bw; 

// 

JO <— . 

A 

io_req; 

// 



ctrl_start ctrl_load; 

// 

CNT <— 

0 

io_is_ack: 




mar_br pc_bw; 

// 

MAR <— 

PC 

pc_Inc; 

// 

PC++ 


md r_b r r am_bw; 

// 

MDR <— 

RAM [mar] 

ioa_br mdr_bw; 

// 

IOA <— 

MDR 

// 




mar_br pc_bw; 


// MAR 

<— PC 

b 

o 

1 

H 

3 

O 

> • 


// PC++ 


md r_b r r am_bw ; 


// MDR 

<— RAM [mar] 

a_br io_bw io_isack; 


// A <- 

- I/O is ack 

a_br alu_f=not_a alu_bw 

fl_ar ; 

// A <- 

- NOT A 

a_br alu_f=not_a alu_bw 

fl_ar ; 

// A <- 

- NOT A 

pc_br sel_f=if_not_zero 

s el_bw 

// pc = 

(7 0 ? MAR : PC) 

ctrl_start ctrl_load; 


// CNT 

<— 0 

end 






602 


A simple 8-bit CPU: version "A" 


Figure 9.153. Match between the contents of the memory that 
represents the microcode (the couple of memory banks ml and 
m2 inside the control unit) and the microcode description itself. 


% 


\t>. \*> \ 5 ' hi -f 

\%\i .s 1 ! .§/ 

\ \ / / ' 


<$z 

Ov/ 


•'O 


H \ 

VZ. \ 


■°j 

-O; 


'<$■/ 

5 / vjv / 


\%> \ Si 

\?. \B 


■ ^ ; v. ^ 

a -4/ 

1 ■ ^ /; 


1/4/ #<£/ 


& \ s e/ <?/ <?/ <? ' 


8 / *... jP/ 

-O/ -07 'P/' f> 

a/ #/ 4’/ #/'' 


\ \ i i m / 


M r ? a// 


XMi r f // 


r t / />" 



4 4 


o / / 


C?/ O / 

S/ -£/ 

q/; j 

$T: Ol 
/ co; 

\« 

fs 


VtS 


.V v 

<£/ 0=not A \ \ 

1 =A and B \$> \<? 

V 2=A or B 

3=A xor B ^ 

4=A « 1 
5=A » 1 
6=A « 1 arith 
7=A » 1 arith 
8=A rot left 
9=A rot right 
A=A rot carry left 
B=A rot carry right 
C=A plus B carry 
D=A minus B borrow 
E=A plus B 
F=A minus B 


4 

^ / 0=if carry 

-Q/ 1=if not carry 

Qj/ 2=ifzero 

/ 3=if not zero 

4=if negative 
5=if not negative 
6=if overflow 
7=if not overflow 














































































































































































A simple 8-bit CPU: version "A" 


603 


Table 9.154. Macroinstructions added for this version of the sim¬ 


ple CPU. 


Syntax 

Description 

in io_address 

It reads a byte from the I/O address 
specified by the argument. 

out io_address 

It writes a byte to the I/O device 
specified by the argument. 

io_is_ack io_address fref 

It reads a byte from the I/O device 
specified by the first argument. If 
the byte read is FFi 6 that means ac¬ 
knowledge and it jumps to the ad¬ 
dress specified as the second argu¬ 
ment. 


9.8.7 Instruction "out" 

Listing 9.155. Macrocode to experiment the use of out and 
io_is_ack. The program just shows the letter ‘H’ in a loop, 
without stop. The complete source file should be available at 
attachments/xcpu/xcpu-a8-out.gm . 

begin macrocode @ 0 
start: 

load_ref fcharacter 
move_mdr_a 

out 0 // display 

check_ack: 

io_is_ack 0, #start 
jump #check_ack 

stop: 

stop 









604 


A simple 8-bit CPU: version "A" 


character: 


.byte 0x48 

end 

// 'H' 


Video: ogv http://www.youtube.com/watch?v=S9XqmTMYAj4 . 

9.8.8 Instruction "in" 


Listing 9.156. Macrocode to experiment the instruction in: the 
keyboard is read and the character read is output again with the 
out instruction, through the display. The complete source file 
should be available at attachments/xcpu/xcpu-a8-in.gm . 


begin macrocode @ 0 
start: 


stop: 
end 


in 1 

not 

not 

jump_if_zero #start 
out 0 

jump #start 
stop 


Video: ogv http://www.youtube.com/watch?v=JhGoQhssWQM . 




“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


Chapter 


Version "B": optimization 

10.1 Uniform registers . 608 

10.2 Module “RAM” . 610 

10.3 Module “SEL” . 615 

10.4 Module “ALU”. 615 

10.5 Module “TTY”: the terminal. 616 

10.6 Module “CTRL”: control unit. 622 

10.7 Memories, fields, arguments and opcodes . 626 

10.8 Microcode . 644 

10.9 Macrocode: routine call . 664 

10.10 Macrocode: keyboard input and screen output . 666 

10.11 Version “B2”. 668 


Here is proposed a restructuring of the simple CPU developed up 
to this point, to rearrange and simplify its operation. Version “Bl” 
starts from the implementation of uniform registers, up to an opti¬ 
mization of the operation, avoiding unnecessary clock cycles. 


Attachments 

Description 

attachments/xcpu/xcpu-bl. v 

TKGate Verilog netlist source file. 

attachments/xcpu/xcpu-bl .gm 

TKGate microcode and 

macrocode source file. 

attachments/xcpu/xcpu-bl - 
terminal.vpd.tcl 

TCL/Tk script related to the termi¬ 
nal module TTY. 



















606 


Version "B": optimization 


Attachments 

Description 

attachments/xcpu/xcpu-b2. v 

TKGate Verilog netlist source file. 

attachments/xcpu/xcpu-b2.gm 

TKGate microcode and 

macrocode source file. 

attachments/xcpu/xcpu-b2- 

terminal.vpd.tcl 

TCL/Tk script related to the termi¬ 
nal module TTY . 








Version "B": optimization 


607 


Figure 10.2. Simple CPU version “Bl”. 
































































































608 


Version "B": optimization 


10.1 Uniform registers 


All the registers of the new simple CPU have the opportunity to in¬ 
crease and reduce the value that they contain, by one unit; moreover, 
they have the ability to read data from the bus ( B ) or from an auxil¬ 
iary input (Z). In order to monitor their activity, these registers have 
two outputs where LEDs could be connected: these outputs are acti¬ 
vated when reading or writing is requested. 

Figure 10.3. Generalized registers, external appearance. 

register content copy 


clear, clock 


control lines 


b 0 clear 
b x clock 


auxiliary data input 


test point: active when the 
register is loading a value 


A 

t 


b o 

b i 

b 2 

b 3 

b 4 

bus read 
bus write 
extra read 
increment 

c 

D 

C 

decrement 

X 





i 

B 

0 




* 




data bus 

/ 


\ test piont: active when the 
\ register is writing to the bus 










Version "B": optimization 


609 


Figure 10.4. Generalized register: internal structure. 



-)E>o 

UL 

£ 

i± 

Q o 

IQ_ IO 

O IO 





t 


c 

D 

C 

X 



i 

B 

0 


t 




































































































































































610 

10.2 Module "RAM 


Version "B": optimization 


The RAM module may receive the address directly from the regis¬ 
ters PC , SP , I and /, without mediation, so the MAR used until the 
earlier version is now removed. The choice of the address register to 
read depends on the code contained in the group of lines of the C 
input. 

Figure 10.5. Module RAM , external appearance. 


register PC register J 



The internal diagram of the RAM module changes substantially, al¬ 
lowing to use the address from the selected register, but only at the 
state in which this data is valid. In the diagram there is the addition 
of a module, called H , which is a register controlled by an enable 
input line (it does not react only at the clock edge). This kind of 
register is used to maintain stored a value for all the time in which 












Version "B": optimization 


611 


the input H is asserted (zero, as it is a complemented input line), 
otherwise it is traversed transparently by the data. 

Figure 10.6. Module RAM , internal structure. 


C 

V 



In this version of the CPU, during a clock cycle, the address used to 
locate a memory cell may not be stable, due to various factors. First 
of all, the address is selected, by a multiplexer, from four different 
registers, but this selection can be done at the start of the T phase 
shown inside the next figure; therefore, in this first phase the address 
received by the RAM module changes in the majority of cases. Then, 
when the clock signal changes from zero to one, the address source 
register might be updated in preparation for the next step. Therefore, 
the valid information from the address used for the RAM appears 



































612 


Version "B": optimization 


just before the clock positive edge (phase ‘II’). However, when it is 
required to write a value in the RAM, the RAM itself needs to have 
the address for a certain time, during which this address should not 
change: this is done with the H module that is transparent when the 
signal clock is zero, while it blocks its value when the clock signal is 
active. For that reason, the RAM is enabled for receiving a request to 
read or write only during the active period of the clock signal (phase 
‘HI’). When the RAM is just read, it is sufficient that the RAM has 
had time to provide the data corresponding to the address selected 
when the information is then loaded from the bus by another register. 

Inside the figure, the graph 4 A’ refers to the ranges of validity of 
the address information, around the positive variation of the clock 
signal. The graph ‘B’ shows the situation at the output of module H, 
which extends the validity of the incoming address, because when 
the clock signal becomes positive, the module H blocks the value at 
its output. The graph ‘C’ shows the period in which it is granted to 
the RAM memory to change its content (RAM write). 


Figure 10.7. Functional phases for the RAM module. 








_ A 








clock 


data 

valid 

< - V 


data 

valid 

<—> 



held data 

'< - > 


c 


held data 

< -> 


clock 








B 

clock 






valid data 

and held 

^ _ w. 


valid data 

and held 

_ w. 

clock 


111 


111 

i 


1 



a 


a 


The module H is made of simple SR flip-flops, connected so as to 

























































Version "B": optimization 


613 


operate as D flip-flops, with the enable input. Simple flip-flops with 
enable input are used to avoid the introduction of excessive latencies. 



614 


Version "B": optimization 


Figure 10.8. Module H {hold), internal structure. 



A 


preset 


- i 

> 


►- 


T>= 


► - > 


clear 


a 


I CL 


A A 
10 n 





















































































































615 


Version "B": optimization 

10.3 Module "SEL" 


The selection module is not changed, except for the reorganization 
of the wiring and the addition of a diagnostic output to know when 
the evaluated condition is fulfilled (output t). 


Figure 10.9. Module SEL , internal structure. 


b0 = carry 
bl = zero 
/b2 = negative 
b3 = overflow 


c >- 


4 

3:1 

- 7^ - 

o 1 



/ dec 


control 


CO = bus write 
C3:1 = func 

C = 01: if carry 
C = 03: if not carry 
C = 05: if zero 
C = 07: if not zero 
C = 09: if negative 
C = 11: if not negative 
C = 13: if overflow 
C = 15: if not overflow 



bus write = select 


B 


10.4 Module "ALU 


Also the ALU module is not substantially changed from the previous 
one: the control lines are joined together and there is a new diagnos¬ 
tic indicator (output o ) that is active when the module writes to the 
bus. 













































































616 


Version "B": optimization 


Figure 10.10. Module ALU , internal structure. 


b0 = carry 
bl = zero 
/ s b2 = negative 
b3 = overflow 


IT 


\° v, 


rrn 



control 


C=01: NOT A (Carry and Overflow unchanged) 

C=03: A AND B (Carry and Overflow unchanged) 

C=05: A OR B (Carry and Overflow unchanged) 

C=07: A XOR B (Carry and Overflow unchanged) 

C=09: logic shift left 

C=11: logic shift right 

C=13: arithmetic shift left 

C=15: arithmetic shift right 

C=17: rotation left 

C=19: rotation right 

C=21: rotation left with carry 

C=23: rotation right with carry 

C=25: A plus B with carry 

C=27: A minus B with carry 

C=29: A plus B with no carry 

C=31: A minus B with no carry 


/4 



v- 


bus write = select 


B 




bO = carry 
bl = zero 
b2 = negative 
b3 = overflow 


Fo 


10.5 Module "TTY": the terminal 


The terminal, made of the keyboard-screen group, is different from 
the previous version of the simple CPU, because it is unified, as it 
is implemented already for the TKGate library. However, the uni¬ 
fication internally maintains the circuit distinction of the previous 
version and also the same operating logic; in practice, keyboard and 
screen continue to be managed separately, but the TCL/Tk imple¬ 
mentation code is made of a single module, which manifests itself in 
a single window during the TKGate simulation. 












































































































































Version "B": optimization 


617 


Figure 10.11. Module TTY , internal structure. 



In the figure that shows the circuit of the TTY module there is a 
different area distinguishing the two portions, related to keyboard 
and screen: it should be noticed that the two blocks are activated via 


different addresses (input A), exactly as it is in the previous version. 
The terminal module is written in Verilog, as already done in the 
previous version, but in this case it is a single module, for keyboard 
and screen. In turn, the terminal module uses TCL/Tk code that is 
contained in the file ‘terminal .tel’ shown immediately after the 
Verilog code. 





























































































































Version "B": optimization 


Listing 10.12. Module terminal , written in Verilog. 

module terminal(K_DATA, K_REQ, K_ACK, 

S_DATA, S_REQ, S_ACK, CLR); 

output K_ACK; 
output S_ACK; 
output [7:0] K_DATA; 
input [7:0] S_DATA; 
input K_REQ; 
input S_REQ; 
input CLR; 
reg k_ready; 
reg [7:0] key; 
reg s_ready; 

initial 

begin 

k_ready = 0; 
s_ready = 0; 
key = 0; 
end 

always 

begin 

@(posedge CLR) 
k_ready = 0; 
s_ready = 0; 
key = 0; 
end 



Version "B": optimization 


initial $tkg$post("TERMINAL", 

always 

begin 

@ (posedge K_REQ); 

# 5; 

key = $tkg$recv("%m.KD") ; 

# 5; 

k_ready = l'bl; 

# 5; 

@ (negedge K_REQ); 

# 5; 

k_ready = 1'bO; 
end 

always 

begin 

@ (posedge S_REQ); 

# 5; 

$tkg$send("%m.SD",S_DATA) 

# 5; 

s_ready = l'bl; 

# 5; 

@ (negedge S_REQ); 

# 5; 

s_ready = 1'bO; 
end 


assign S_ACK = s_ready; 




620 


Version "B": optimization 


assign K_DATA = key; 
assign K_ACK = k_ready; 

endmodule 


Listing 10.13. File ‘share/tkgate/vpd/terminal. tel’. The 

file is similar to the one included in the TKGate library, for the 
terminal management. 

image create bitmap txteurs -file "$bd/txtcurs.b" 

VPD::register TERMINAL 
VPD::allow TERMINAL::post 
VPD::allow TERMINAL::data 

namespace eval TERMINAL { 

# Public variables declarations: the variables $terminal_... 

# are arrays of which only the element $n is used; 

# that element identifies uniquely the working interface instance. 

variable terminal_w 
variable terminal_pos 

# 

variable KD 

# Function requested by TKGate to create the interface. 

proc post {n} { 

variable terminal_w 
variable terminal_pos 

# Create the window and save the object element in a $terminal_w array element. 

set terminal_w($n) [VPD::createWindow "TERMINAL $n" -shutdowncommand "TERMINAL::unpost $n"] 

# For convenience, copy the object reference inside the local 

# variable $w; then, the variable $w will be used as a reference to the object. 

set w $terminal_w($n) 
text $w.txt -state disabled 
pack $w.txt 

# Put the cursor at the end of the displayed text. 

$w.txt image create end -image txteurs 

# Bind the keyboard input, related to the object represented by 

# $terminal_w ($n), to the function sendChar. 

bind $ w <KeyPress> " TERMINAL :: sendChar $n \"%A\ If " 

# Open a reading channel, named «SD» (screen data), 

# and associate it to the function «data»; moreover, open a 

# writing channel, named «KD» (keyboard data). 

if {[info exists ::tkgate_islnitialized]} { 

VPD::outsignal $n.KD TERMINAL::KD($n) 

VPD::insignal $n.SD -command "TERMINAL::data $n" -format %d 

} 

# Reset the character count, used to count the characters displayed 




Version "B": optimization 


621 


# on screen. 

set terminal_pos($n) 0 

} 

# Function that receives the typing and put It Into the 

# channel «KD», related to the current Interface Instance. 

proc sendChar {n key} { 
variable KD 

if { [string length $key ] == 1 } { 
binary scan $key c c 
set TERMINAL::KD($n) $c 

} 

} 

# Function that TKGate requires to destroy the interface. 

proc unpost {n} { 

variable terminal_w 
variable terminal_pos 
destroy $terminal_w($n) 
destroy $terminal_pos($n) 
unset terminal_w($n) 
unset terminal_pos($n) 

} 

# Function used to get the data to display on screen. 

proc data {n c} { 

variable terminal_w 
variable terminal_pos 

# For convenience, copy the object reference representing the 

# interface, inside the variable $w. 

set w $terminal_w($n) 
catch { 

# The variable $c contains the character to display. 

if { $C == 7 } { 

# BEL 

bell 

return 

} elseif { $c == 127 | | $c == 8 } { 

# DEL I BS 

if { $terminal_pos($n) > 0 } { 

# Delete the last displayed character, but only if the 

# characters counter is greater than zero, otherwise 

# the cursor would disappear and the next characters 

# would be located in an invisible screen area. 

$w.txt configure -state normal 
$w.txt delete "end - 3 chars" 

$w.txt see end 

$w.txt configure -state disabled 

set terminal_pos($n) [expr {$terminal_pos($n) - l}] 

} 

return 

} elseif { $c == 13 } { 

# Convert CR to LF. 

set c 10 

} 



622 


Version "B": optimization 


# Convert the character number into a visible symbol . 

set x [format %c $c] 

# Display the symbol . 

$w.txt configure -state normal 
$w.txt insert "end - 2 chars" $x 
$w.txt see end 

$w.txt configure -state disabled 

# Update the displayed characters counter. 

set terminal_pos($n) [expr {$terminal_pos($n) + l}] 

} 

} 

} 


10.6 Module "CTRL": control unit 


To simplify the organization of the wiring, the control unit incorpo¬ 
rates the generator of clock pulses; moreover, the generator of clock 
pulses incorporates the management of the reset signal, so that it is 
removed only at the more suitable time for the impulse clock: up to 
the previous version of the simple CPU, the circuit required a man¬ 
ual reset before the CPU could work properly, but the release of the 
reset signal could happen at an unsuitable time, which made it all 
unstable. 


Figure 10.14. Timing for the clear line. 


clock 


clear line 


input R 


y 

power on 


clear signal disabled 
automatically 


y 

clock pulses start 


input R asserted 


y 

input R negated 


the clear line is negated after 
a little while, sincronously 


the clear line is asserted with a little delay 

































































Version "B": optimization 


623 


The following picture shows the block diagram of the control unit 
that integrates the clock functionality. In the left part is the circuit 
that generates the clock pulses and controls the clear line. The mod¬ 
ule fdiv is extended compared to the previous version, in order to 
be able to divide more the frequency. The frequency selection is 
made through a multiple switch (dip switch) connected to a multi¬ 
plexer that is seen at the top. However, the experiments with TKGate 
show that the CPU can operates with a maximum clock frequency 
of 1.25 MHz that is produced setting this switch to the value 1. 



624 Version "B": optimization 

Figure 10.15. Control unit with the clock generator. 
































































































































Version "B": optimization 


625 


There are different fdiv modules inside the control unit: the central 
one is used to count the pulses to synchronize the reset line, the 
rightmost is used to count clock pulses from the start for diagnostic 
purposes, giving the counted value through the t output. 

On the right part of the figure that represents the original control unit, 
there is a unique 16-bit counter ( MCP ) and it lacks the opportunity 
to restore the execution of the microcode from the beginning (ad¬ 
dress zero). The two least significant bit of the control word are used 
to carry the clock pulse and the reset signal (clear); the same two 
least significant lines that come out from the memory that contains 
the microcode, are used to control the module itself and do not affect 
the rest of the CPU. This version of the control unit does not allow 
to resume the clock signal after the internal stop line is asserted. 


Figure 10.16. Connections to the control bus. 



On the picture above there are some components of the simple CPU, 
connected to the control bus. All these components have in common 
the c input (lowercase) and the C input (upper case). The c input is 
always connected to the first two lines of the bus control, from which 
it is obtained, respectively, the reset signal and the clock signal. The 
C input, instead, must be connected to the lines of the control bus 
that specifically relate to the module. In the case of generalized reg- 




















626 


Version "B": optimization 


isters, these lines are always five: bus_read , bus_write , extra_read , 
increment , decrement. The PC register connects its C input to the 
lines 2 to 6 (C 6 „ 2 ) of the control bus; the module SPL (which uses 
only four control lines) is connected to the lines 7 to 10 (C 10 .. 7 ), and 
so is with the other components. 

10.7 Memories, fields, arguments and opcodes 


The TKGate source used to describe the contents of the memory 
used by the simple CPU, always begins with the definition of the 
memory dimensions, along with each bank name: 


map 

bank[7:0] 

Ctrl.map; 

microcode 

bank[31:0] 

Ctrl.micro0; 

microcode 

bank [63:32] 

Ctrl.microl; 

microcode 

bank [91:64] 

Ctrl.micro2; 

macrocode 

bank[7:0] 

ram.ram; 


In this version of the simple CPU there are some changes to the 
memory names, in order to make clearer each respective task. It 
should be noticed that three memory modules, each of 32 bits, are 
used for the microcode word, because the control bus requires the 
use of many lines. 


field 

Ctrl[1:0] 

= {nop=0 

, stop= 

=1, load=2}; 

field 

pc[6:2 ] 

= {br=l. 

bw=2, 

xr=4, inc=8, dec=16}; 

field 

sel [10:7] 

= {if_carry=l. 

if_not_carry=3. 



if_zero=5. 

if_not_zero=7, 



if_negative 

= 9, if_not_negative=ll. 



if_overflow 

=13, if_not_overflow=15}; 

field 

mdr[15:11] 

= {br=l. 

bw=2, 

xr=4, inc=8, dec=16}; 

field 

j [20:16] 

= (br=l. 

bw=2, 

xr=4, inc=8, dec=16}; 

field 

ram[24:21] 

= {br=l. 

bw=2, 

p=0, i=4, j=8, s=12}; 

field 

ir[29:25] 

= {br=l. 

bw=2, 

xr=4, inc=8, dec=16}; 

field 

sp[34:30] 

= {br=l. 

bw=2, 

xr=4, inc=8, dec=16}; 





Version "B": optimization 


627 


field 

i [39:35] 

\-1 

II 

u 

II 

bw=2, xr=4. 

inc=8, dec=16}; 

field 

b [44 : 40] 

\—1 

II 

u 

II 

bw=2, xr=4. 

inc=8, dec=16}; 

field 

fl [49:45] 

\—1 

II 

u 

II 

bw=2, xr=4. 

inc=8, dec=16}; 

field 

alu[54:50] 

= (not=l 

and=3, or= 

5, xor=7, lshl=9, lshr=ll. 



ashl= 

13, ashr=15, 

rotl=17, rotr=19, rotcl=21. 



rot cr 

=23, add_c=25, sub_b=27, add=29, sub=31}; 

field 

a [59:55] 

*—1 

II 

u 

II 

bw=2, xr=4. 

inc=8, dec=16}; 

field 

ioa[64:60] 

= {br=l. 

bw=2, xr=4. 

inc=8, dec=16}; 

field 

ioc[68:65] 

< 

\-1 

II 

u 

II 

bw=2, req=4 

, isack=8}; 


The control word fields are written in a more compact manner. It 
should be noticed that values that can be represented in each field 
may be added with the binary OR operator. In practice, in relation to 
the field pc, which refers to the PC register control lines, both the 
writing to the data bus (pc=bw) and the increment (pc=inc) could 
be turned on, during the same clock cycle. 

Inside the Ctrl field declaration there are the first two lines, used for 
the stop clock and microinstruction load, but it is worth to remaind 
that those two lines are not connected to the control bus outside, 
because in their place there are the clear and clock lines. 

In this version of the project it is possible to declare a null microin¬ 
struction, with the sole purpose of waiting a clock cycle. This mi¬ 
croinstruction is selected with: ctrl=nop. 


The opcode remains 8-bit long, then, there may be a maximum of 
two arguments (8 bits each): 


operands 

op 0 

{ 

— = 

{ }; 


}; 



operands 

op 1 

{ 

#1 = 

{ 

= # 1 [ 7 : 0 ] ; }; 






628 


Version "B": optimization 


}; 

operands op_2 { 
#1, #2 = { +1 = 

}; 

=#1 [7:0]; +2=#2 [15:8] ; }; 

The opcode of the available macroinstructions is simply an integer 

that starts from zero, matching the nop instruction, ending with 255 

which matches the stop instruction. There are no other considera- 

tions. 


op nop { 

// not operate 

map nop: 0; 


+ 

O 

<1 

• • 

o 

1_1 

II 

o 

> • 


operands op 0; 


}; 


op load 

// MDR < — RAM [arg] 

{ 


map load: 1; 


+0[7:0]=1 ; 


operands op 1; 


}; 


op load i 

// MDR <— RAM[±] 

{ 


map load_i : 2; 


+0 [ 7 : 0 ] =2 ; 


operands op 0; 


}; 


op load j 

// MDR <— RAM[j] 

{ 


map load_j : 3; 


+ 0 [7:0] =3; 





Version "B": optimization 


629 


operands op 0; 

}; 

op store { 

// RAM[arg] < — MDR 


map store: 4; 

+ 0 [7:0]=4; 
operands op 1; 

}; 

op store_i { 

// RAM[i ] < — MDR 


map store_i: 5; 

+ 0 [7:0]=5; 
operands op 0; 

}; 

op store_j { 

// RAM[j] <— MDR 


map store_j: 6; 

+ 0 [ 7:0]= 6; 
operands op_0; 

}; 

op cp_ij { 

// RAM[j++] <— MDR 

<— RAM [i++ ] 

map cp_ij: 7; 

+ 0 [ 7:0]=7; 
operands op_0; 

}; 

op cp_ji { 

// RAM[i++] <— MDR 

<— RAM[j++] 

map cp_ji: 8; 

+0[7:0]=8; 
operands op 0; 

}; 

op mv_mdr_a { 

// A <— MDR 


map mv_mdr_a: 9; 

+ 0 [7:0]=9; 





630 


Version "B": optimization 


operands op_0; 


J ' 

op mv_mdr_b { 

// B < — MDR 

map mv_mdr_b: 

+ 0 [7:0]=10; 
operands op_0; 

\. 

10; 

J r 

op mv_mdr_f1 { 

// FL < — MDR 

map mv_mdr_fl: 
+ 0 [7:0]=11; 
operands op_0; 

\ . 

li; 

J r 

op mv_mdr_sp { 

// SP <— MDR 

map mv_mdr_sp: 
+0[7:0]=12; 
operands op_0; 

12; 

j' 

op mv_mdr_i { 

// J <— MDR 

map mv_mdr_i: 

+ 0 [7:0]=13; 
operands op_0; 

13; 

j' 

op mv_mdr_j { 

// J <— MDR 

map mv_mdr_j: 
+0[7:0]=14; 
operands op_0; 

14; 

j' 

op mv_a_mdr { 

// A <— MDR 

map mv_a_mdr: 

+ 0 [7:0]=15; 

15; 



Version "B": optimization 


631 


operands op 0; 

}; 


op mv_a_b { 

map mv_a_b : 16; 

+0[7:0]=16; 
operands op 0; 

}; 

// B <— A 

op mv_a_f1 { 

map mv_a_fl: 17; 
+0[7:0]=17 ; 
operands op 0; 

}; 

// FL < — A 

op mv_a_sp { 

map mv_a_sp: 18; 
+0[7:0]=18; 

operands op_0; 

X. 

// SP <— A 

f t 

op mv_a_i { 

map mv_a_i: 19; 

+ 0 [7:0]=19; 

operands op_0; 

X. 

// I <— A 

I' 

op mv_a_j { 

map mv_a_j : 20; 

+ 0 [ 7 : 0 ] =2 0 ; 

operands op_0; 

X. 

// J <— A 

I' 

op mv_b_a { 

map mv_b_a : 21; 

+ 0 [ 7:0 ] =21; 

// A <— B 



632 


Version "B": optimization 


operands op_0; 


J ' 

op mv_b_mdr { 

map mv_b_mdr: 22; 
+ 0[7:0]=2 2; 
operands op_0; 

\ . 

// MDR <— B 

J r 

op mv_b_f1 { 

map mv_b_fl: 23; 
+0[7:0]=23; 
operands op_0; 

\. 

// FL <— B 

J r 

op mv_b_sp { 

map mv_b_sp: 24; 

+ 0[7:0]=2 4; 

operands op_0; 

l. 

// SP <— s 

J' 

op mv_b_i { 

map mv_b_i: 25; 

+ 0 [7:0]=25; 

operands op_0; 

l. 

// I <— B 

J' 

op mv_b_j { 

map mv_b_j: 26; 

+ 0 [ 7:0]=2 6; 

operands op_0; 

l. 

// J <— B 

J' 

op mv_fl_a { 

map mv_fl_a: 27; 

+ 0 [7:0]=27; 

// A <— FL 



Version "B": optimization 


633 


operands op_0; 

\ . 


J r 

op mv_fl_b { 

map mv_fl_b: 28; 

+ 0[7:0]=2 8; 
operands op_0; 

\ . 

// B <— FL 

J r 

op mv_fl_mdr { 

map mv_fl_mdr: 29 
+ 0 [7:0]=2 9; 
operands op_0; 

\ . 

// MDR <— FL 

} 

J r 

op mv_fl_sp { 

map mv_fl_sp: 30; 
+0[7:0]=30; 

operands op_0; 

l. 

// SP <— FL 

J' 

op mv_fl_i { 

map mv_fl_i: 31; 
+0[7:0]=31; 

operands op_0; 

l. 

// I <— FL 

J' 

op mv_fl_j { 

map mv_fl_j: 32; 
+0[7:0]=32; 

operands op_0; 

l. 

// J <— FL 

J' 

op mv_sp_a { 

map mv_sp_a: 33; 
+0[7:0]=33; 

// A <— SP 



634 


Version "B": optimization 


operands op_0; 


J ' 

op mv_sp_b { 

map mv_sp_b: 34; 
+0[7:0]=34; 
operands op_0; 

\ . 

// B < — SP 

J r 

op mv_sp_fl { 

map mv_sp_fl: 35; 
+0[7:0]=35; 
operands op_0; 

\ . 

// FL <— SP 

J r 

op mv_sp_mdr { 

map mv_sp_mdr: 3 6 
+ 0 [7:0]=3 6; 

operands op_0; 

l. 

// MDR <— SP 

• 

r 

J' 

op mv_sp_i { 

map mv_sp_i: 37; 
+0[7:0]=37; 

operands op_0; 

l. 

// I <— SP 

J' 

op mv_sp_j { 

map mv_sp_j: 38; 
+0[7:0]=38; 

operands op_0; 

l. 

// J <— SP 

J' 

op mv_i_a { 

map mv_i_a: 39; 

+ 0 [7:0]=3 9; 

// A <— I 



Version "B": optimization 


635 


operands op 0; 

}; 


op mv_i_b { 

map mv_i_b: 40; 

+ 0 [ 7:0]=4 0; 
operands op 0; 

}; 

// B <— I 

op mv_i_fl { 

map mv_i_f1: 41; 

+ 0 [7:0]=41; 
operands op 0; 

}; 

// FL < — J 

op mv_i_sp { 

map mv_i_sp: 42; 

+ 0 [7:0]=42; 
operands op_0; 

// SP < — J 

f t 

op mv_i_mdr { 

map mv_i_mdr: 43; 

+ 0 [7:0]=43; 

operands op_0; 

l. 

// MDR <— I 

J' 

op mv_i_j { 

map mv_i_j: 44; 

+0[7:0]=44; 

operands op_0; 

l. 

// J <— I 

J' 

op mv_j_a { 

map mv_j_a: 45; 

+0[7:0]=45; 

// A <— J 



636 


Version "B": optimization 


operands op 0; 

}; 


op mv_j_b { 

map mv_j_b: 46; 

+ 0 [7:0]=4 6; 
operands op 0; 

}; 

// B <— J 

op mv_j_fl { 

map mv_j_fl: 47; 

+ 0 [ 7:0]=4 7; 
operands op 0; 

}; 

// FL <— J 

op mv_j_sp { 

map mv_j_sp: 48; 

+ 0 [ 7:0]=4 8; 
operands op_0; 

// SP <— J 

f t 

op mv_j_i { 

map mv_j_i: 49; 

+ 0[7:0]=4 9; 

operands op_0; 

l. 

// I <— J 

J' 

op mv_j_mdr { 

map mv_j_mdr: 50; 
+0[7:0]=50; 
operands op_0; 

// MDR < — J 

J' 

op j ump { 

map j ump: 51; 

+0[7:0]=51; 

// PC < — arg 



Version "B": optimization 


637 


operands op_l; 

\ . 


j' 

op j ump_c { 

// if carry, PC <— arg 

map j ump_c: 52; 


+0[7:0]=52; 


operands op_l; 


j ' 

op jump_nc { 

// if not carry, PC <— arg 

map j ump_n c: 53; 


+ 0 [7:0]=53; 


operands op_l; 

\ . 


J r 

op jump_z { 

// if zero, PC < — arg 

map jump_z: 54; 


+ 

O 

-J 

• • 

o 

II 

Cn 

> • 


operands op_l; 

l. 


j' 

op j ump_n z { 

// if not zero, PC <— arg 

map j ump_n z: 55; 


+ 0 [7:0]=55; 


operands op_l; 

l. 


j' 

op j ump_n { 

// if negative, PC <— arg 

map j ump_n: 5 6; 


+ 0[7:0]=5 6; 


operands op_l; 

l. 


J' 

op jump_nn { 

// if not negative, PC <— arg 

map jump_nn: 57; 


+ 

O 

-J 

• • 

o 

II 

Cn 

-J 

> • 




638 


Version "B": optimization 


operands op_l; 

X . 


J r 

op j ump_o { 

// if overflow, PC <— arg 

map j ump_o: 5 8; 


+ 

O 

-J 

• • 

o 

II 

Cn 

00 

> • 


operands op_l; 

X . 


J r 

op jump_no { 

// if not overflow, PC <— arg 

map j ump_no: 5 9; 


+ 0 [7:0]=5 9; 


operands op_l; 

X . 


J r 

op call { 


map call : 60; 


+ 

O 

-J 

• • 

o 

II 

(T\ 

O 

> • 


operands op_l; 

1. 


J t 

op call_i { 

// call I 

map call_i: 61; 


+0[7:0]=61; 


operands op_0; 

1. 


J t 

op call_j { 

// call J 

map call_j : 62; 


+0[7:0]=62; 


operands op_0; 


J' 

op return { 


map return : 63; 


+0[7:0]=63; 




Version B : optimization 


operands op_0; 

}; 

op push_mdr { 
map push_mdr: 
+0[7:0]=64; 
operands op_0; 

}; 

op push_a { 

map push_a: 65 
+ 0 [ 7 : 0 ]= 65 ; 
operands op_0; 

}; 

op push_b { 

map push_b: 66 
+ 0 [ 7 : 0 ]= 66 ; 
operands op_0; 

}; 

op push_fl { 

map push_fl: 6 
+ 0 [7:0]=67; 
operands op_0; 

}; 

op push_i { 

map push_i: 68 

+0[7:0]=68; 
operands op_0; 

}; 

op push_j { 

map push_j: 65 

+ 0 [ 7 : 0 ]= 69 ; 




£ 


Version "B": optimization 


operands op_0; 

}; 

op pop_mdr { 

map pop_mdr: 70; 
+ 0[7:0]=7 0; 
operands op_0; 

}; 

op pop_a { 

map pop_a: 71; 

+0[7:0]=71; 
operands op_0; 

}; 

op pop_b { 

map pop_b: 72; 

+0[7:0]=72; 
operands op_0; 

}; 

op pop_fl { 

map pop_fl: 73; 
+0[7:0]=73; 
operands op_0; 

}; 

op pop_i { 

map pop_i: 74; 

+0[7:0]=74; 
operands op_0; 

}; 

op pop_j { 

map pop_j: 75; 

+ 0 [7:0]=75; 




Version B : optimization 


operands op_0; 

}; 

op not { 

map not: 76; 

+ 0[7:0]=7 6; 
operands op_0; 

}; 

op and { 

map and: 77; 

+ 0[7:0]=7 7; 
operands op_0; 

}; 

op or { 

map or: 78; 

+ 0[7:0]=7 8; 
operands op_0; 

}; 

op xor { 

map xor: 79; 

+ 0[7:0]=7 9; 
operands op_0; 

}; 

op lshl { 

map lshl: 80; 

+ 0[7:0]=8 0; 
operands op_0; 

}; 

op lshr { 

map lshr: 81; 
+0[7:0]=81; 




£ 


Version "B": optimization 


XL 

operands op_0; 

}; 

op ashl { 

map ashl: 82; 
+0[7:0]=82; 
operands op_0; 

}; 

op ashr { 

map ashr: 83; 
+0[7:0]=83; 
operands op_0; 

}; 

op rotl { 

map rotl: 84; 

+ 0 [ 7 : 0]=8 4 ; 
operands op_0; 

}; 

op rotr { 

map rotr: 85; 
+0[7:0]=85; 
operands op_0; 

}; 

op rotcl { 

map rotcl: 86; 
+ 0[7:0]=8 6; 
operands op_0; 

}; 

op rotcr { 

map rotcr: 87; 
+0[7:0]=87; 




Version B : optimization 





644 


Version "B": optimization 



10.8 Microcode 

Inside the microcode description section, the first instructions are 
used to load the first opcode, but in this version, only one clock cycle 
is needed: 

begin microcode @ 0 

// 

ir=br ram=bw ram=p pc=inc ctrl=load; // IR <— RAM[pc++], 

// jump MAP[ir]; 

The IR register loads from the data bus what is output from the 
RAM module, which in turn receives the address from the PC regis¬ 
ter, which is also post-incremented. In addition to this, it is required 
to the control unit to update its microprogram-counter (fiPC) with 
the value coming from the memory ctrl.map , associated to the ad¬ 
dress that represents the opcode. All this can be done in a single 
clock cycle because the structure of the CPU has changed from the 
previous version. It should be considered the different phases of the 




Version "B": optimization 


645 


clock cycle, which intervene in different ways in the control unit 
with respect to the components that are then connected to the con¬ 
trol bus, as shown in the next picture. 


Figure 10.22. Fetch clock cycle. 


CPU clock 


clock seen 
by the jiPC 


V 

the control bus is updated 
with the microcode to be 
executed and the pPC 
is prepared to load a 
value , but not immediately 


t 

the microprogram counter pPC 
loads the incoming value, 
which is the microcode address that 
implements the opcode 
received from the IR register 


in the data bus is already the PC value is incremented 
available the opcode 
read from the RAM 

T 


the IR register is updated 
with the value 
read from the data bus 

Therefore, with only one clock cycle, it takes place what is known 
as fetch. In the following instruction description, at the end of each 
procedure the fetch microinstruction is repeated, without the need 





















646 


Version "B": optimization 


to restart the microprogram counter \iPC to the first microinstruc¬ 
tion, as it was necessary in previous versions of the simple CPU. 
In practice, for the macroinstruction nop there is only the fetch mi¬ 
croinstruction: 

nop: 

ir=br ram=bw ram=p pc=inc ctrl=load; // fetch 


It follows the description of the other macroinstructions: 


load: 

i=br ram=bw ram=p pc=inc; 


// 

J <- RAM[pc++] ; 

mdr=br ram=bw ram=i; 


// 

MDR <- RAM[i ]; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

load_i: 

mdr=br ram=bw ram=i; 


// 

MDR <- RAM[i ]; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

load_j: 

mdr=br ram=bw ram=j; 


// 

MDR <- RAM[j]; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

store: 

i=br ram=bw ram=p pc=inc; 


// 

I <- RAM[pc++] ; 

ram=br ram=i mdr=bw; 


// 

RAM[i ] <- MDR; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

store_i: 

ram=br ram=i mdr=bw; 


// 

RAM[i] <- MDR; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

store_j: 

ram=br ram=j mdr=bw; 


// 

RAM[j] <- MDR; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

cp_ij: 

mdr=br ram=bw ram=i i=inc; 


// 

MDR <- RAM[i++]; 

ram=br ram=j mdr=bw j=inc; 


// 

RAM[j++] <- MDR; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

cp_ji: 

mdr=br ram=bw ram=j j=inc; 


// 

MDR <- RAM[ j++]; 

ram=br ram=i mdr=bw i=inc; 


// 

RAM[i++] <- MDR; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

mv_mdr_a: 




Version "B": optimization 


647 



a=br mdr=bw; 




// 

A <- MDR; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_mdr_b: 








b=br mdr=bw; 




// 

B <- MDR; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_mdr_f 1: 








f l=br 

mdr=bw; 




// 

FL <- MDR; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_mdr_sp: 








sp=br 

mdr=bw; 




// 

SP <- MDR; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_mdr_i: 








i=br mdr=bw; 




// 

I <- MDR; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_mdr_j : 








j=br mdr=bw; 




// 

J <- MDR; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_a_mdr: 








mdr=br 

■ a=bw; 




// 

MDR <- A; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_a_b: 








b=br a 

=bw; 




// 

B <- A; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_a_f 1: 








f l=br 

a=bw; 




// 

FL <- A; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_a_sp: 








sp=br 

a=bw; 




// 

SP <- A; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_a_i: 








i=br 

a=bw; 




// 

I <- A; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_a_j : 








j=br 

a=bw; 




// 

J <- A; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_b_a: 








a=br b 

i=bw; 




// 

A <- B; 


ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 


mv_b_mdr: 



648 


Version "B": optimization 



mdr=br b=bw; 




// 

MDR <- B; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_b_f 1: 







£ 

43 

II 

43 

U 

43 

II 

i— l 

4-1 




// 

FL <- B; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_b_sp: 







sp=br b=bw; 




// 

SP <- B; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_b_i: 







£ 

43 

II 

43 

U 

43 

II 

-H 




// 

I <- B; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

b_j: 







j=br b=bw; 




// 

J <- B; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_f l_a: 







a=br fl=bw; 




// 

A <- FL; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_fl_b: 







b=br fl=bw; 




// 

B <- FL; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_f l_mdr: 







mdr=br fl=bw; 




// 

MDR <- FL; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_f l_sp: 







£ 

43 

II 

i —l 

4-4 

U 

43 

II 

CO 




// 

SP <- FL; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_f l_i : 







i=br fl=bw; 




// 

I <- FL; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_fl_j : 







j=br fl=bw; 




// 

J <- FL; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_sp_a : 







a=br sp=bw; 




// 

A <- SP; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ 

_sp_b : 







b=br sp=bw; 




// 

B <- SP; 


ir=br ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 


mv_sp_f1: 



Version "B": optimization 


649 


u 

43 

II 

i—l 

4-1 

sp=bw; 




// 

FL <- SP; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_sp_mdr: 







mdr=br 

sp=bw; 




// 

MDR <- SP; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_sp_i: 







i=br sp=bw; 




// 

I <- SP; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_sp_j: 







j=br sp=bw; 




// 

J <- SP; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_i_a: 







a=br i 

=bw; 




// 

A <- I; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_i_b: 







b=br i 

=bw; 




// 

B <- I; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_i_f1: 







u 

43 

II 

i—l 
4-1 

i=bw; 




// 

FL <- I; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_i_sp: 







sp=br 

i=bw; 




// 

SP <- I; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_i_mdr: 







mdr=br 

i=bw; 




// 

MDR <- I; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_i_j: 







j=br i 

=bw; 




// 

J <- I; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_j_a : 







a=br j 

=bw; 




// 

A <- J; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_ j_b : 







b=br j 

=bw; 




// 

B <- J; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 

mv_j_f1 : 







u 

43 

II 

i — l 

4-i 

j =bw ; 




// 

FL <- J; 

ir=br 

ram=bw 

ram=p 

pc=inc 

ctrl=load; 

// 

fetch 


mv_j_sp: 



650 


Version "B": optimization 


sp=br j=bw; 

// 

$ 

A 

1 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

mv_j_i: 

i=br j=bw; 

// 

I <- J; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

mv_j_mdr: 

mdr=br j=bw; 

// 

MDR <- J ; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

jump: 

i=br pc=bw; 

// 

I <- PC 

pc=br ram=bw ram=i; 

// 

PC < — RAM[i] 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

j ump_c: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++] 

pc=br sel=if_carry; 

// 

PC = (carry ?MDR: PC) 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

jump_nc: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++ ] 

pc=br sel=if_not_carry; 

// 

PC = (not_carry?MDR: PC) 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

jump_z: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++ ] 

pc=br sel=if_zero; 

// 

PC = ( zero?MDR : PC) 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

j ump_n z: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++ ] 

pc=br sel=if_not_zero; 

// 

PC = (not_zero?MDR:PC) 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

j ump_n: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++ ] 

pc=br sel=if_negative; 

// 

PC = (hegati ve ?MDR : PC ) 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

jump_nn: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++] 

pc=br sel=if_not_negative; 

// 

PC = (not_negative?MDR:PC) 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

j ump_o: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++] 

pc=br sel=if_overflow; 

// 

PC = ( overflow?MDR : PC) 



Version "B": optimization 


651 


ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

jump_no: 

mdr=br ram=bw ram=p pc=inc; 

// 

MDR <— RAM [pc++ ] 

pc=br sel=if_not_overflow; 

// 

PC - (not_overflow?MDR:PC) 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

call: 

i=br ram=bw ram=p pc=inc sp=dec; 

// 

I <- RAM[pc++ ] , SP — ; 

ram=br ram=s pc=bw; 

// 

RAM[sp ] <- PC; 

pc=br i=bw; 

// 

PC <- I; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

call_i: 

sp=dec; 

// 

SP —; 

ram=br ram=s pc=bw; 

// 

RAM[sp] <- PC; 

pc=br i=bw; 

// 

PC <- I; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

call_j: 

sp=dec; 

// 

SP —; 

ram=br ram=s pc=bw; 

// 

RAM[sp] <- PC; 

pc=br j=bw; 

// 

PC <- J; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

return: 

pc=br ram=bw ram=s sp=inc; 

// 

PC <- RAM[sp++] ; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

push_mdr: 

sp=dec; 

// 

SP —; 

ram=br ram=s mdr=bw; 

// 

RAM[sp ] <- MDR; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

push_a: 

sp=dec; 

// 

SP —; 

ram=br ram=s a=bw; 

// 

RAM[sp] <- A; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

push_b: 

sp=dec; 

// 

SP —; 

ram=br ram=s b=bw; 

// 

RAM[sp] <- B; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 

push_f1: 

sp=dec; 

// 

SP —; 

ram=br ram=s fl=bw; 

// 

RAM[sp] <- FL; 

ir=br ram=bw ram=p pc=inc ctrl=load; 

// 

fetch 



652 


Version "B": optimization 


push_i: 

sp=dec; 


// 

SP —; 

ram=br ram=s i=bw; 


// 

RAM[sp] <- I; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

push_j: 

sp=dec; 


// 

SP — ; 

ram=br ram=s j=bw; 


// 

RAM[sp] <- J; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

pop_mdr: 

mdr=br ram=bw ram=s sp=inc 

} 

// 

MDR <- RAM[sp++] ; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

pop_a: 

a=br ram=bw ram=s sp=inc; 


// 

A <- RAM[sp++]; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

pop_b: 

b=br ram=bw ram=s sp=inc; 


// 

B <- RAM[sp++] ; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

pop_f1: 

fl=br ram=bw ram=s sp=inc; 


// 

FL <- RAM [ sp++ ]; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

pop_i: 

i=br ram=bw ram=s sp=inc; 


// 

I <- RAM[sp++] ; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

pop_j: 

j=br ram=bw ram=s sp=inc; 


// 

J <- RAM[sp++] ; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

not: 

a=br alu=not fl=xr; 


// 

A <- NOT A; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

and: 

a=br alu=and fl=xr; 


// 

A <- A AND B 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

or: 

a=br alu=or fl=xr; 


// 

A <- A OR B 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

xor: 

a=br alu=xor fl=xr; 


// 

A <- A XOR B 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

lshl: 



Version "B": optimization 


653 


a=br alu=lshl fl=xr; 


// 

A <- A « 1 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

lshr: 

a=br alu=lshr fl=xr; 


// 

A <- A » 1 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

ashl: 

a=br alu=ashl fl=xr; 


// 

A <- A*2 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

ashr: 

a=br alu=ashr fl=xr; 


// 

A <- A/2 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

rot 1: 

a=br alu=rotl fl=xr; 


// 

A <- rotl(A) 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

rotr: 

a=br alu=rotr fl=xr; 


// 

A <- rotr (A) 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

rotcl: 

a=br alu=rotcl fl=xr; 


// 

A <- rotcl (A) 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

rotcr: 

a=br alu=rotcr fl=xr; 


// 

A <- rotcr (A) 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

add_c: 

a=br alu=add_c fl=xr; 


// 

A <- A+B+carry 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

sub_b: 

a=br alu=sub_b fl=xr; 


// 

A <- A-B-borrow 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

add: 

a=br alu=add fl=xr; 


// 

A <- A+B 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

sub: 

a=br alu=sub fl=xr; 


// 

A <- A-B 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

in: 

ioa=br ram=bw ram=p pc=inc; 

// 

IOA <- RAM[pc++]; 

ioc=req; 


// 

I/O request; 

ctrl=nop; 


// 

does not do anything 



654 


Version "B": optimization 


a=br ioc=bw; 


// 

A <- I/O 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

out: 

ioa=br ram=bw ram=p pc=inc 

r 

// 

IOA <- RAM[pc++]; 

ioc=br a=bw; 


// 

I/O <- A 

ioc=req; 


// 

I/O request; 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

is_ack: 

ioa=br ram=bw ram=p pc=inc 

r 

// 

IOA <- RAM[pc++]; 

mdr=br ram=bw ram=p pc=inc 

r 

// 

MDR <- RAM[pc++] ; 

a=br ioc=bw ioc=isack; 


// 

A <- I/O is ack; 

a=br alu=not fl=xr; 


// 

A <- NOT A; 

a=br alu=not fl=xr; 


// 

A <- NOT A; 

pc=br sel=if_not_zero; 


// 

PC = (not_zero?MDR: PC); 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

stop: 

ctrl=stop; 


// 

stop clock 

// if resumed: 

ir=br ram=bw ram=p pc=inc 

ctrl=load; 

// 

fetch 

end 


The set of macroinstructions has changed slightly and it is also ex¬ 
tended, taking into account the changes to the CPU, as described in 
the following table. 


Table 10.25. Macroinstruction list for the current simple CPU. 


Syntax 

Clock 

cycles 

Description 

nop 

1 

Do nothing: just fetch the next 
instruction. 

load address 

3 

The instruction loads the ar¬ 
gument into the I register and 
then loads into the MDR reg¬ 
ister the memory content at 
the specified address. 









Version "B": optimization 


655 


Syntax 

Clock 

cycles 

Description 

load_i 

load_ j 

2 

The instruction loads into the 
MDR register the memory 
content at the address speci¬ 
fied by the I or J register. 

store address 

3 

The instruction loads the ar¬ 
gument into the I register and 
then it writes the MDR con¬ 
tent into the memory, at the 
address specified. 

store_i 

store_j 

2 

The instruction writes the 
MDR content into memory, at 
the address specified by the I 
or J register. 

c P_i j 

c P_ji 

3 

The first instruction copies the 
memory content from the ad¬ 
dress specified by the I regis¬ 
ter to the address specified by 
the J register. The second in¬ 
struction does the opposite. 




)6 

Version "B": optimization 

Syntax 

Clock 

cycles 

Description 

mv_mdr_a 



mv_mdr_b 



mv_mdr_f 1 


Copy the content of the MDR 


2 

register to the register A, B, 

mv_mdr_sp 


FL, SP, I or J. 

mv_mdr_i 



mv_mdr_ j 



mv_a_mdr 



mv_a_b 



mv_a_f 1 


Copy the content of the A reg¬ 


2 

ister to the register MDR, B, 

mv_a_sp 


FL, SP, I or J. 

mv_a_i 



mv_a_ j 






Version "B": optimization 


0 Clock 

Syntax , 

cycles 

Description 

mv_b_a 


mv_b_mdr 


mv_b_f 1 

Copy the content of the B reg¬ 

2 

ister to the register A, MDR, 

mv_b_sp 

FL, SP, I or J. 

mv_b_i 


mv_b_ j 


mv_f l_a 


mv_fl_b 


mv_fl_mdr 

Copy the content of the FL 

2 

register to the register A, B, 

mv_fl_sp 

MDR, SP, I or /. 

mv_fl_i 


mv_f1_j 





Version B : optimization 


Syntax 


Clock 

cycles 


Description 


mv_sp_a 


mv_sp_b 


mv_sp_f1 


mv_sp_mdr 


Copy the content of the SP 
register to the register A, B, 

FL, MDR, I or /. 


mv_sp_i 


mv_sp_j 


mv 1 a 


mv i b 


mv i f 1 


mv_i_sp 


Copy the content of the I reg¬ 
ister to the register A, B, FL, 

SP, MDR or J. 


mv i mdr 


mv_i_i 




Version "B": optimization 


659 


Syntax 

Clock 

cycles 

Description 

mv_ j_a 



mv_ j_b 



mv_j_f1 

2 

Copy the content of the J reg¬ 
ister to the register A, B, FL, 

mv_ j_sp 


SP, I or MDR. 

mv_ j_i 



mv_j_mdr 





Jump to the specified address: 

j ump address 

3 

it puts the argument into the I 

W/ 

register and then jumps to the 
instruction at that address. 





660 


Version "B": optimization 


Syntax 


j ump_c 


address 


Clock 

cycles 


Description 


j ump_n c address 
jump_z address 
j ump_n z address 
j ump_n address 
jump_nn address 
j ump_o address 


These instructions put the ar¬ 
gument inside the MDR reg¬ 
ister, then, if the condition im¬ 
plied by the name is true, they 
jumps to the instruction at the 
address specified. The condi¬ 
tions are in this order: carry, 
not carry, zero, not zero, neg¬ 
ative, not negative, overflow, 
not overflow. 


j ump_n o address 


call address 


Call a procedure: it puts the 
argument into the I register 
and it decrement the SP regis¬ 
ter, then, it saves the PC reg¬ 
ister to the memory address 
contained inside the SP regis¬ 
ter (it is a push). Then it jumps 
to the address specified. 




Version "B": optimization 


661 


Syntax 

Clock 

cycles 

Description 



Call a procedure: it decrement 
the SP register, then, it saves 

call_i 


the PC register to the mem¬ 

call_ j 

4 

ory address contained inside 
the SP register (it is a push). 
Then it jumps to the address 
specified by the register I or 

J. 



Return from procedure call: 
it reads the value contained 

return 

2 

in memory at the SP posi¬ 
tion and it writes that value 
to the PC register, then incre¬ 
ment the SP register. 

push_mdr 



push_a 


Save a register on to the stack: 
it decrements the SP regis¬ 

push_b 


ter, then, at the new address 
specified by the SP register, 

push_f1 

3 

it writes in memory the value 
of the register named as an 

push_sp 


extension to the instruction 
name. That is: MDR , A, B, 

push_i 


FL, SP, I or J. 

push_ j 






)Z 


Version "B": optimization 

Syntax 

Clock 

cycles 

Description 

pop_mdr 



pop_a 


Restore a register from the 

pop_b 


stack: it copies inside the 
specified register the memory 

pop_f 1 

3 

content at the position speci¬ 
fied by the SP register, then it 

pop_sp 


increments the same SP reg¬ 
ister. 

pop_i 



pop_j 



not 

2 

A <— 

and 


A <- A &B 

or 

2 

A <- A 1 B 

A <- A A B 

xor 



lshl 


A <(— left or right logic shift of 




Version "B": optimization 


663 


Syntax 

Clock 

cycles 

Description 

ashl 

O 

A <(— left or right arithmetic 

ashr 

Z 

shift of A 

rotl 

2 

A <(— left or right rotation of A 

rot 1 



rotcl 


A t- left or right rotation with 

rotcl 

Z 

carry of A 

add_c 





A t- A+/?+carry 

sub_b 

z 

A A-B-carry 

add 

o 

A <r~ A+B 

sub 

z 

A <r- A-B 



Read from I/O device: it reads 

in io_address 


from the I/O address specified 


•J 

and the result is placed inside 
the register A. 



Write to an I/O device: it 

out io_address 

4 

writes the content of register 



A to the I/O device with the 
address specified. 




664 


Version "B": optimization 


Syntax 

Clock 

cycles 

Description 

is_ack io_address address 

7 

Jump if previous I/O opera¬ 
tion is acknowledged: it loads 
the specified I/O address into 
the MDR register and, if the 
device returns a positive ac¬ 
knowledge, it jumps to the last 
argument address. The oper¬ 
ation destroys the A register 
content and updates the flags. 

stop 

1 

Halt: it stops the clock. 


The following sections provide some examples to verify the opera¬ 
tion of macroinstructions with the current version of the simple CPU. 
The examples are combined with videos where also the RAM access 
is highlighted. 


10.9 Macrocode: routine call 

begin macrocode @ 0 
start: 

load #data_3 // Place the stack. 

mv_mdr_sp 

call #sum // Call the function sum(). 

stop 

sum: 

load #data_0 
mv_mdr_a 
load #data_l 









Version "B": optimization 


665 


mv_mdr_b 

add 

mv_a_mdr 
store #data_2 
return 

data_0 : 

.byte Oxll 

data_l: 

.byte 0x12 

data_2 : 

.byte 0x00 

data 3: 


end 


.byte 0x30 




666 


Version "B": optimization 


Figure 10.27. Data bus after the execution of the code 
listed above. Video: ogv http://www.youtube.com/watch?v= 
eATz3XLYWbc 



00 : 01 14 Oc 3c 06 ff 01 11 09 01 12 Oa 5a Of 04 13 
10 : 3f 11 12 23 30 xx xx xx xx xx xx xx xx xx xx xx 
20 : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 05 
30 : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
40 : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
50 : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 


Last Read Access 


Last Write Access 


Address: 06 

Data: 8'hl 

Time: 11.6821ms 


Address: 13 

Data: 8'h23 

Time: 10.3632ms 

ismis 





10.10 Macrocode: keyboard input and screen 
output 


begin macrocode @ 0 



start: 



in 1 

// 

Read from the keyboard. 

not 

// 

Complement two times 

not 

// 

just to update the 
















































































































































































































Version "B": optimization 


667 




// 


jump_z #start 

// 



// 



// 


out 0 

// 



// 


jump #start 

// 

stop: 


// 


stop 

// 

end 




status flags. 

If the value is zero, 
then repeat the 
keyboard read. 

Otherwise, display the 
same value on screen. 

Restart. 

It will never reach this 
point. 


Figure 10.29. Keyboard input and screen output. Video: ogv 
http://www.youtube.com/watch?v=m22oK22ULTwWo 


TkGate: TERMINAL main.gl33.g22 














































































































668 

10.11 Version "B2" 


Version "B": optimization 


Here is described a further modification to the simple CPU, in or¬ 
der to slightly improve its efficiency through a direct connection be¬ 
tween the RAM module and the IR register, so that an opcode can 
be transferred from the memory to the instruction register without 
interfering with the data bus. 


Version "B": optimization 


669 


Figure 10.30. Simple CPU, version “B2”. 





































































































670 


Version "B": optimization 


To make the connection shown in the figure, the RAM module is 
modified, in order to drive an auxiliary output (X); consequently, 
it enlarges its connection to the control bus, forcing to readapt the 
control field position of the other modules. 


Figure 10.31. Module RAM modified with the addition of the 
auxiliary output. 



ing of the control lines on the RAM module, together with the shift 
on the connection of the other modules: 


field Ctrl[1:0] = {nop=0, stop=l, load=2}; 

field pc[6:2] = {br=l, bw=2, xr=4, inc=8, dec=16}; 

field sel[10:7] = {if_carry=l, if_not_carry=3, 














































Version "B": optimization 


671 


if_zero=5, if_not_zero=7, 
if_negative=9, if_not_negative=ll, 
if_overflow=13, if_not_overflow=15}; 


field 

mdr[15:11] 

= 

{br=l. 

cm 

II 

£ 

xr=4, 

inc=8, 

dec=l6}; 

field 

j [20:16] 

= 

{br=l. 

CM 

II 

£ 

xr=4, 

inc=8, 

CD 
*—1 

II 

o 

CD 

T3 

field 

ram[25:21] 

= 

{br=l, 

bw=2, 

xw=4, 

P=0, i 

=8, j=16, s=24}; 

field 

ir[30:26] 

= 

{br=l. 

CM 

II 

£ 

A 

xr=4, 

inc=8, 

CD 
^—1 

II 

o 

CD 

T3 

field 

sp[35:31] 

= 

{br=l. 

CM 

II 

£ 

A 

xr=4, 

inc=8, 

CD 

T-1 

II 

o 

CD 

T3 

field 

i[40:36] 

= 

{br=l. 

CM 

II 

£ 

xr=4, 

inc=8, 

dec=l6}; 

field 

b [45 : 41] 

= 

{br=l, 

CM 

II 

£ 

X3 

xr=4, 

inc=8, 

dec=l6}; 

field 

fl[50:46] 

= 

{br=l, 

CM 

II 

<: 

xr=4, 

inc=8, 

dec=l6}; 

field 

alu[55:51] 

= 

{not=l 

, and= 

3, or= 

5, xor= 

7, lshl=9, lshr=ll. 




ashl= 

13, ashr=15, 

rotl=17, rotr=19, rotcl=21. 




rot cr 

=23, add_c=25, sub_ 

b=27, add=29, sub=31}; 

field 

a[60:5 6] 

= 

{br=l, 

CM 

II 

£ 

A 

xr=4, 

inc=8, 

CD 

y—1 

II 

o 

CD 

T3 

field 

ioa[65:61] 

= 

{br=l, 

CM 

II 

£ 

A 

xr=4, 

inc=8, 

CD 
*— I 

II 

O 

CD 

T3 

field 

ioc[69:66] 

= 

{br=l, 

CM 

II 

£ 

req=4 

, isack 

=8}; 


The difference inside the microcode declaration, is due to the fact 
that the RAM must have enabled the line xr to be able to communi¬ 
cate with the IR register, therefore, all the microinstruction for the 
fetch should be changed in the following way: 

ir=br ram=xw ram=p pc=inc ctrl=load; 


Finally, where possible, the fetch microinstruction that appears at the 
end of each macroinstruction procedure, is merged with the second 
to last microinstruction 1 . It is possible precisely with the instructions 
for copying a value from one register to another and those that do 
something with the ALU: 

mv_mdr_a: 

a=br mdr=bw ir=br ram=xw ram=p pc=inc ctrl=load; 
mv mdr b: 





672 


Version "B": optimization 


b=br mdr=bw ir=br ram=xw ram=p pc=inc ctrl=load; 
mv_j_i: 

i=br j=bw ir=br ram=xw ram=p pc=inc ctrl=load; 
mv_j_mdr: 

mdr=br j=bw ir=br ram=xw ram=p pc=inc ctrl=load; 


not: 








a=br 

alu=not 

f l=xr 

ir=br 

ram=xw 

ram=p 

pc=inc 

ctrl=load; 

and: 








a=br 

alu=and 

f l=xr 

ir=br 

ram=xw 

ram=p 

pc=inc 

ctrl=load; 

add: 








a=br 

alu=add 

f l=xr 

ir=br 

ram=xw 

ram=p 

pc=inc 

ctrl=load; 

sub: 








a=br 

alu=sub 

f l=xr 

ir=br 

ram=xw 

ram=p 

pc=inc 

ctrl=load; 


1 The penultimate microinstruction 




“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


Chapter 

Version "C": 16-bit little-endian 


11.1 General purpose 16-bit registers. 676 

11.2 Module “BUS” . 680 

11.3 Module “ALU”. 681 

11.4 Module “SEL” . 692 

11.5 Module “RAM” . 693 

11.6 Module “IRQ”. 695 

11.7 Module “IVT”. 707 

11.8 Module “CTRL”. 710 

11.9 Opcodes . 713 

11.10 Microcode . 742 

11.11 Interrupts management. 762 

11.12 Module “RTC”: real time clock . 765 

11.13 Module “TTY”. 766 

11.14 Module “HDD” . 772 


11.15 Macrocode: terminal usage example, through interrupts 
780 


Here is a further extension of the project with 16-bit registers, while 
continuing to manage a memory organized in 8-bit words. Since the 
TKGate microcode-macrocode compiler stores the 16-bit values by 
















674 


Version "C": 16-bit little-endian 


reversing the order of the bytes (or at least it does in the version 
compiled for x86 architecture), this version of the CPU (which is 
now a computer with devices) is organized in little-endian mode. 


Attachments 

Description 

attachments/xcpu/xcpu-c. v 

TKGate Verilog netlist source file. 

attachments/xcpu/xcpu-c. gm 

TKGate microcode and 

macrocode source file. 

attachments/xcpu/xcpu-c- 

terminal.vpd.tcl 

TCL/Tk script related to the termi¬ 
nal module TTY. 








Version "C" 


16-bit little-endian 


675 


Figure 11.2. Simple CPU version “C”. 



irq_signal 

















































































































































































676 


Version "C": 16-bit little-endian 


Among the other new things, in the figure should be observed the 
presence of the BP register (base pointer) whose purpose is to fa¬ 
cilitate the use of the stack of data when performing function calls. 
The register should be used in a manner similar to the 8086-8088 
calling conventions; otherwise, the same register is known with the 
name “FP” (frame pointer). 

11.1 General purpose 16-bit registers 


The registers of this version of the project have a 16-bit size, but 
they are divided into two bytes, the contents of which can be ac¬ 
cessed separately. Furthermore, it is possible to increase and reduce 
the value of these registers, of one or two units. 


Figure 11.3. 16-bit registers: external appearance. 


b\5' h register content copy 


h clear j 
b\ clock K 


test point: active when the register 
is loading a value from the main 
bus (B) or from the auxiliary bus (X) 


c D 

C 

i X 

B o 


h 

b 2 


b 6 

b 7 


bus read (load) 
bus write 

auxiliary bus (read/write) 
select byte BO: 7:0 
select byte Bl: 15:8 
plus 1 (register+=l) 
plus 2 (register+=2) 
minus 1 (register-=l) 
minus 2 (register-=2) 


test point: active when the register is 
writing a value to the main bus (B) 
or to the auxiliary bus (X) 


£ i5> . auxiliary bus connection 


\ b\$ * b 0 main bus connection 













load 


Version "C": 16-bit little-endian 


677 


Figure 11.4. 16-bit registers: internal structure. 






































































































678 


Version "C": 16-bit little-endian 


Figure 11.5. Modules H8 and L8. 



The module BYTESELECT contained inside the 16-bit registers, 
is used to reduce the reading of the register content to only 8 bits, 

































































































































































































































































































Version "C": 16-bit little-endian 


679 


choosing from the least significant byte or the more significant one. 
For example, if the register value is ABCDi 6 and the least significant 
byte is selected, the value 00CDi 6 is obtained; on the other hand, if 
the more significant byte is selected, the value 00ABi 6 is obtained. 

When a value is to be written inside the register, the separate mod¬ 
ules H8 and L8 can load independently. If a single byte is to be writ¬ 
ten, to the most significant position inside the register (without mod¬ 
ifying the least significant one), the input from the bus is swapped 
by the module BYTESWAP and the H8 loads alone. 


Figure 11.6. Module BYTESWAP. 


t 

f8 

Lo 

Ho 

oliI _ BYTESWAP 


swap 


Li 

Hi 

* 

t 


swap > 



Hot 


t Lo 




















680 


Version "C": 16-bit little-endian 


Figure 11.7. Module BYTESELECT . 



11.2 Module "BUS" 

For this version of the project there is a new module that allows the 
control unit to write a value to the data bus. The module can select 
the main bus ( B ) or the auxiliary bus (Z). 


























Version "C": 16-bit little-endian 


681 


Figure 11.8. Module BUS. 


t t 

x B 

BUS 

c 

t 


18 

0 — 7 ^ 


bus write 



X B 


11.3 Module "ALU 



The ALU unit is redesigned from the previous version of the project. 
Currently is it able to handle 16-bit values and some more functions. 
It should be noticed that there are separated flags for 8-bit and 16-bit 
operations. 


























682 


Version "C": 16-bit little-endian 


Figure 11.9. ALU overall structure. 




negatives - 





































































































































































Version "C": 16-bit little-endian 


683 


Figure 11.10. Login unit inside the ALU. 


A 

V 



C=0: q = a 
C=1: q = a AND B 
C=2: q = a OR b 
C=3: q = a XOR b 
C=4: q = NOT (a XOR b) 
C=5: q = NOT (a OR b) 
C=6: q = NOT (a AND b) 
C=7: q = NOT a 


c>- 


yono 


^ 1 . 



16 


/ 16 


t 

Q 


m> 




















































684 


Version "C": 16-bit little-endian 


Figure 11.11. Module AS : addition and subtraction. 



borrow out 
















































Version "C": 16-bit little-endian 


685 


Figure 11.12. Module FAS (full adder-subtractor) that is found 
inside the arithmetic unit. The fa modules are just standard full 
adders. 



v 

CO 







































































































686 


Version "C": 16-bit little-endian 


Figure 11.13. Module SH , used for bit shift and rotation with 
carry. 




































































Version "C": 16-bit little-endian 


687 


Figure 11.14. Module ROT : rotation without carry. 


A 

V 



-<c 


Y 

s 





















































688 


Version "C": 16-bit little-endian 


Figure 11.15. Module sh used inside the shift and rotation mod¬ 
ules. 


rout 

right out A 


nn 

v right in 


0=logic shift 
1 =arithmetic shift 

la > 


right 

side 

carry 



> Cr 


[1] Arithmetic shift: 

- the shift should be arithmetic; 

- it should be a right shift; 

- the most significant bit should be L 

[2] Overflow: 

- the shift should be arithmetic; 

- the most significant bit should not 
have changed . 

[3] Connection to the most significant 
digit or to the sign . 

[4] Connection to the least significant digit 
[Cl] Left carry: 

- it should be a left shift; 

- the original most significant digit is L 
[Cr] Right carry: 

- it should be a right shift; 

- the original least significant digit is L 


lr 


0=left 

l=right 


overflow 

o 


ci 


carry 


A left in 

lin 


v left out 

lout 
















































































































Version "C": 16-bit little-endian 


689 


The current ALU is able to modify the flags through the FAS mod¬ 
ule (flags add-subtract). As already pointed out, there is a couple of 
flags, to distinguish between 8-bit and 16-bit results. For example 
there is a 8-bit carry and another 16-bit carry. When the flags are 
modified through the FAS module, both flags are changed; that is, 
if the carry flag is changed, this modification is applied to both 8-bit 
and 16-bit carry flags. The FAS module receives a 8-bit mask and 
the function to be applied (bitwise AND or bitwise OR), to change 
the flags status. 


Figure 11.16. Module FSR : direct flags status change. 






Fo t 











































































690 Version "C": 16-bit little-endian 

The module SHORFILL is used inside the ALU to reduce the size 
of a result: if the size reduction is requested, then the most significant 
byte is filled. If the value is unsigned or positive, the most significant 
byte is zeroed, otherwise is set to all ones, to extend the sign (if no 
size reduction is requested, no modification is applied). 



Version "C": 16-bit little-endian 


691 


Figure 11.17. Module SHORTFILL , for size reduction. 






































Version "C": 16-bit little-endian 


692 

11.4 Module "SEL" 


The SEL module is extended to handle the distinguished register 
sets, for eight or sixteen bits. There is also a new flag used to en¬ 
able hardware interrupts (IRQ), but there are not branch conditions 
related to the interrupt flag status; that is why the SEL module just 
ignores the interrupt flag. 


Figure 11.18. Module SEL. 


+ + + 




CO = bus write 
C3:1 =func 


C = 01: if carry 8-bit 
C = 03: if not carry 8-bit 
C = 05: if zero 8-bit 
C = 07: if not zero 8-bit 
C = 09: if negative 8-bit 
C = 11: if not negative 8-bit 
C = 13: if overflow 8-bit 
C = 15: if not overflow 8-bit 


C = 17: if carry 16-bit 
C = 09: if not carry 16-bit 
C = 21: if zero 16-bit 
C = 23: if not zero 16-bit 
C = 25: if negative 16-bit 
C = 27: if not negative 16-bit 
C = 29: if overflow 16-bit 
C = 31: if not overflow 16-bit 



0 7 


bO = carry 8-bit 
bl = zero 8-bit 
b2 = negative 8-bit 
b3 = overflow 8-bit 
b4 = interrupt enable 

b8 = carry 16-bit 
b9 = zero 16-bit 
bl 0 = negative 16-bit 
bl 1 = overflow 16-bit 
b12 = interrupt enable 



bus write = select 















































































































Version "C": 16-bit little-endian 


693 


11.5 Module "RAM" 

The RAM memory continues to be organized in 8-bit words, as it 
happens for common architectures. To read or write a 16-bit value, it 
is necessary to access two times: as the architecture is little-endian, 
read and write start always from the least significant byte. 


Figure 11.19. Module RAM. 



x B 

The RAM module contains DH16 that is a register that repeats on 
the Q output the value received form the D input, as long as the input 













































































694 


Version "C": 16-bit little-endian 


H is negated (active, as the meaning of the line is complemented): 
when the input line H is asserted (hold), the output Q is frozen. 

Figure 11.20. The steps to build DHn modules: it all starts from a 
SR latch with enable input; than it becomes a D latch and finally 
these D latch are put together in parallel. Obviously, the module 
DH16 is made with two modules DH8, which is made with two 
modules, DH4. 




























































































Version "C": 16-bit little-endian 


695 


11.6 Module "IRQ" 

This version of the simple CPU handles interrupts, distinguishing 
between those produced internally by the CPU itself, those gener¬ 
ated by external devices and those managed by software. The IRQ 
module is responsible to collect hardware interrupts from the de¬ 
vices, to sort interrupts by a priority, to supply the selected interrupt 
to the control circuit that must then do something with it. In short, 
the module receives IRQ interrupts asynchronously, it stores and de¬ 
termines which is the interruption to be served first. The module 
appears externally as if it were a register, since it must be able to 
receive an interrupt mask and the same mask can be read from the 
module. 


696 


Version "C": 16-bit little-endian 


Figure 11.21. Module IRQ : full schema. 



To understand what really does the IRQ module, it is necessary to 
analyze its components, with the help of a block diagram, shown in 
the next figure. 













































































































































































Version "C": 16-bit little-endian 


697 


Figure 11.22. Block diagram for the IRQ module. 


IRQ 



interrupt 

number 


bus dati 

It is simpler to start from the analysis of the register that contains the 
IRQ mask, which is located at the bottom left of the overall scheme: 
it is a 4-bit register (one for each IRQ) which reads data from the 
bus to update its value and writes to the data bus to allow to know 
the value that it contains. 






















698 


Version "C": 16-bit little-endian 


Figure 11.23. IRQ mask detail. 


IRQ register 



B 


The DR4 module is a 4-bit register, made of D flip-flops, through 
the following steps. 



















































Version "C": 16-bit little-endian 


699 


Figure 11.24. Building DRn modules. 



In the upper left of the overall scheme, it appears the IRQ register, 
whose purpose is to store the hardware interrupts received from the 
input IRQ . this register is constructed in an unusual way, because it 
is made by D flip-flops, positive edge, but the D inputs of these flip- 
flops is connected so as to be always active, while the clock input is 
used to receive the IRQ signal. In practice, an IRQ signal arriving at 
the flip-flop clock line, activates permanently the flip-flop. The IRQ 
register flip-flops can be reset to zero only asserting the input line C. 














































































700 


Version "C": 16-bit little-endian 


Figure 11.25. Received IRQ register. 








































































Version "C": 16-bit little-endian 


701 


The value stored inside the IRQ register and the value from the IRQ 
mask below, are compared with a multiple AND gate (a separate 
gate for each IRQ line) and then given to a module that selects one 
IRQ line according to a priority: the lowest IRQ number requested is 
chosen. The module responsible for the priority selection communi¬ 
cates with an encoder that takes care of transforming the IRQ chosen 
into a number of interruption: IRQO becomes INT4, IRQ1 becomes 
INT5, up to IRQ3 which becomes INT7. It should be noticed that 
the priority selection module emits a signal ( irq_set ) about the ac¬ 
tual presence of an IRQ that needs to be served, because the absence 
of an IRQ produces anyway the value INT4 through the encoder. 



702 


Version "C": 16-bit little-endian 


Figure 11.26. Priority selection and encoder. 































































Version "C": 16-bit little-endian 


703 


When an IRQ has been served, there is the need to reset the matching 
D flip-flop in the IRQ register (top left). To obtain this result a reset 
register is used (it appears at the top right). The reset register is made 
of D flip-flops (positive edge) which under normal conditions (when 
the input irq_done is zero) produce at their output a value equal to 
1, since they are initialized to 1 (input P to 0). The output of the 
reset register is connected to the C input of the IRQ register: as long 
as the C lines of the IRQ register are negated (in that case it means 
that the lines are active) the IRQ register retains its stored value. 
However, when the reset register receives the signal irq_done it gets 
and store the complemented IRQ (selected by the priority); that is: 
the last selected IRQ becomes 0 inside the reset register and then, 
asserts the matching C input line of the IRQ register, resetting it. At 
that point, the priority module might select a new IRQ requesting to 
be served. 



704 


Version "C": 16-bit little-endian 


Figure 11.27. Served IRQ reset register. 



The C inputs at the IRQ register on the left are not connected directly 
to the served IRQ reset register, because it might be necessary to 
reset the whole IRQ register, through the control reset line. For this 
reason, there is an AND gate to handle that situation. 

The served IRQ reset register might be designed in a more compact 
way, as the following picture shows. 





































































































Version "C": 16-bit little-endian 


705 


Figure 11.28. served IRQ reset register, made of a module D4. 



The module Dn is made of D flip-flops, in parallel, as the following 
figure shows. 



























706 


Version "C": 16-bit little-endian 


Figure 11.29. Building Dn modules. 


p > 


Ck > 


D > 


C > 



Q Q 
















































































































































Version "C": 16-bit little-endian 


707 


11.7 Module "IVT" 

In order to manage interruptions (CPU, hardware and software), this 
version of the simple CPU needs to have an IVT table (interrupt 
vector table), which resides in RAM memory. The table IVT must 
be implemented as an array of 16-bit integers (little-endian), each 
of which represents the address of a routine to execute when the 
matching interrupt is enabled. Therefore, IVT[n] must match the 
address of the routine that has to perform the activity requested by 
the interrupt n . 

The module IVT is used to store the location of the IVT table, which 
is precisely the location of IVT[0]. The module receives the number 
of a certain interruption from two independent inputs; such interrupt 
number is then transformed into the matching address in memory 
that contains the reference to the requested routine to be started. 


708 


Version "C": 16-bit little-endian 


Figure 11.30. Module IVT. 



A 


c 












































Version "C": 16-bit little-endian 


709 


Inside the IVT module there is a register represented by the mod¬ 
ule DR16. The module DR16 is used to store the IVT table starting 
address. The module DR16 is made in the same manner already de¬ 
scribed for the module DR4, inside the previous section. The module 
ADD16 is made of sixteen full adders, connected in parallel with a 
cascade carry. Even the ADD 16 module is made through different 
stages, as it is for DR16. 

Figure 11.31. Building modules ADDn. 


<N 



S 



































































Version "C": 16-bit little-endian 


710 

11.8 Module "CTRL" 

The module CTRL has only minor changes from the previous ver¬ 
sion: the opcode occupy only eight bits (input /), the microprogram 
counter (fiPC) is reduced to only nine bits, because the microcode 
does not exceed 512 lines, the microcode word requires many more 
bits, so, five memory modules are used together to drive a control 
bus of 160 bits. The input to the microprogram counter is mediated 
by a multiplexer that permits to enter an address when the D flip- 
flop on the right is active. This address must match the point where 
the microcode describes the steps required to serve a hardware in¬ 
terrupt (IRQ); in practice, such address must match the irq label 
placement, as it can be determined from the files produced by the 
TKGate compiler. 


Version "C": 16-bit little-endian 


711 


Figure 11.32. Module CTRL. 

i 























































































































































712 


Version "C": 16-bit little-endian 


Figure 11.33. Control unit detail. 


Microcode Symbols 


iret 00000169 



c 


Looking at the figure above, it is important to clarify what hap¬ 
pens when a hardware interrupt is received: the IRQ module, as de¬ 
scribed in section 11.6, sends to the IVT module the interrupt num¬ 
ber matching the selected IRQ to be served; then, the IRQ module 
activates the Is output (interrupt set). The interrupt-set line activated 







































































Version "C": 16-bit little-endian 


713 


by the IRQ module, reaches the control unit only if the interrupt- 
enable flag (/) is active. When the interrupt request reaches the mod¬ 
ule CTRL at the input Is , it is stored into the D flip-flop (positive 
edge) that appears in the upper right of the diagram; then, at the first 
occasion in which the control unit must read a new opcode, it is in¬ 
stead directed to execute the instructions matching the label irq. 


Listing 11.34. Memory banks declaration. 


map 

bank [7:0] 

Ctrl.map; 

microcode 

bank [31:0] 

Ctrl.micro0; 

microcode 

bank [63:32] 

Ctrl.microl; 

microcode 

bank[95:64] 

Ctrl.micro2; 

microcode 

bank[127:96] 

Ctrl.micro3; 

microcode 

bank [15 9:128] 

Ctrl.micro4; 

macrocode 

bank [15:0] 

ram.ram; 


11.9 Opcodes 

The opcode size used in this version of the simple CPU, remains 
limited to eight bits, but instead of using just a sequential number 
to distinguish them, the opcodes are now structured with a criterion. 
First there is a definition used to convert register names to integer 
numbers, so that three bits are requested to distinguish them: 

registers 1=0, J=l, A=2, B=3, BP=4, SP=5, MDR=6, FL=7; 


There are different kind of operands; the simplest cases are declared 
at the beginning: 

operands op_0 { 

- = { }; 





714 


Version "C": 16-bit little-endian 



It is understood that op_0 means the request of no operand at all; 
that op_8 requires an 8-bit operand; that op_16 requires a 16-bit 
operand. For the 16-bit operand it is requested to read two separate 
bytes, starting from the least significant one, because the byte order 
organization is little-endian. 


Listing 11.37. Opcodes declaration. 


op nop { 









map nop: 

0x00; 

// 

not operate 




+0[7:0]=0x00; 









operands op_0; 

\. 









J' 

op mv { 


// 

00 . 

= 

mv 




map nop: 

0x00; 

// 

00000000 

= 

mv 

%I 

%I not 

valid => nop 

map mv_i_j: 

0x01; 

// 

00000001 

= 

mv 

%I 

%J 


map mv_i_a: 

0x02; 

// 

00000010 

= 

mv 

%I 

%A 


map mv_i_b: 

0x03; 

// 

00000011 

= 

mv 

%I 

%B 


map mv_i_bp: 

0x0 4; 

// 

00000100 

= 

mv 

%I 

%BP 


map mv_i_sp: 

0x05; 

// 

00000101 

= 

mv 

%I 

%SP 


map mv_i_mdr: 

0x06; 

// 

00000110 

= 

mv 

%I 

%MDR 


map mv_i_f1: 

0x0 7; 

// 

00000111 

= 

mv 

%I 

%FL 


map mv_j_i: 

0x0 8; 

// 

00001000 

= 

mv 

%J 

%I 


map op_error: 

0x0 9; 

// 

00001001 

= 

mv 

%J 

%J not 

valid 

map mv_j_a: 

OxOA; 

// 

00001010 

= 

mv 

%J 

%A 


map mv_j_b: 

OxOB; 

// 

00001011 

= 

mv 

%J 

%B 








Version "C": 16-bit little-endian 


715 


map 

mv_j_bp : 

OxOC; 

// 

OOOOllOO 

= 

mv 

%J 

%BP 



map 

mv_j_sp: 

0 x 0 D; 

// 

OOOOllOl 

= 

mv 

%J 

%SP 



map 

mv_j_mdr : 

0 x 0 E; 

// 

OOOOlllO 

= 

mv 

%J 

%MDR 



map 

mv_j_f 1 : 

OxOF; 

// 

OOOOllll 

= 

mv 

%J 

%FL 



map 

mv_a_i: 

0x10; 

// 

OOOIOOOO 

= 

mv 

%A 

%I 



map 

mv_a_j : 

0x11; 

// 

OOOlOOOl 

= 

mv 

%A 

%J 



map 

op_error : 

0x12; 

// 

OOOIOOIO 

= 

mv 

%A 

%A not 

valid 

map 

mv_a_b : 

0x13; 

// 

OOOlOOll 

= 

mv 

%A 

%B 



map 

mv_a_bp : 

0x14; 

// 

OOOIOIOO 

= 

mv 

%A 

%BP 



map 

mv_a_sp : 

0x15; 

// 

OOOIOIOI 

= 

mv 

%A 

%SP 



map 

mv_a_mdr : 

0x16; 

// 

00010110 

= 

mv 

%A 

%MDR 



map 

mv_a_f 1: 

0x17; 

// 

OOOlOlll 

= 

mv 

%A 

%FL 



map 

mv_b_i : 

0x18; 

// 

OOOllOOO 

= 

mv 

%B 

%I 



map 

mv_b_j : 

0x19; 

// 

OOOllOOl 

= 

mv 

%B 

%J 



map 

mv_b_a: 

OxlA; 

// 

OOOllOlO 

= 

mv 

%B 

%A 



map 

op_error : 

OxlB; 

// 

OOOllOll 

= 

mv 

%B 

%B not 

valid 

map 

mv_b_bp : 

OxlC; 

// 

OOOlllOO 

= 

mv 

%B 

%BP 



map 

mv_b_sp : 

OxlD; 

// 

OOOlllOl 

= 

mv 

%B 

%SP 



map 

mv_b_mdr : 

0 x 1E; 

// 

OOOllllO 

= 

mv 

%B 

%MDR 



map 

mv_b_f 1: 

OxlF; 

// 

OOOlllll 

= 

mv 

%B 

%FL 



map 

mv_bp_i : 

0x20; 

// 

OOIOOOOO 

= 

mv 

%BP 

%I 



map 

mv_bp_j : 

0x21; 

// 

OOlOOOOl 

= 

mv 

%BP 

%J 



map 

mv_bp_a : 

0x22 ; 

// 

OOIOOOIO 

= 

mv 

%BP 

%A 



map 

mv_bp_b: 

0x23; 

// 

OOlOOOll 

= 

mv 

%BP 

%B 



map 

op_error: 

0x2 4 ; 

// 

OOIOOIOO 

= 

mv 

%BP 

%BP not 

valid 

map 

mv_bp_sp: 

0x25; 

// 

OOIOOIOI 

= 

mv 

%BP 

%SP 



map 

mv_bp_mdr: 

0x26; 

// 

OOlOOllO 

= 

mv 

%BP 

%MDR 



map 

mv_bp_f1: 

0x2 7; 

// 

OOlOOlll 

= 

mv 

%BP 

%FL 



map 

mv_sp_i: 

0x28; 

// 

OOIOIOOO 

= 

mv 

%SP 

%I 



map 

mv_sp_j: 

0x2 9; 

// 

OOIOIOOI 

= 

mv 

%SP 

%J 



map 

mv_sp_a: 

0x2A; 

// 

OOIOIOIO 

= 

mv 

%SP 

%A 



map 

mv_sp_b: 

0x2B; 

// 

OOlOlOll 

= 

mv 

%SP 

%B 



map 

mv_sp_bp: 

0x2C; 

// 

OOlOllOO 

= 

mv 

%SP 

%BP 



map 

op_error : 

0x2D; 

// 

OOlOllOl 

= 

mv 

%SP 

%SP not 

valid 

map 

mv_sp_mdr : 

0x2E; 

// 

OOlOlllO 

= 

mv 

%SP 

%MDR 



map 

mv_sp_f 1 : 

0x2F; 

// 

OOlOllll 

= 

mv 

%SP 

%FL 








716 


Version "C": 16-bit little-endian 


map mv_mdr_i: 

0x30; 

// 

00110000 

= 

mv %MDR %I 

map mv_mdr_j: 

0x31; 

// 

00110001 

= 

mv %MDR %J 

map mv_mdr_a: 

0x32; 

// 

00110010 

= 

mv %MDR %A 

map mv_mdr_b: 

0x33; 

// 

00110011 

= 

mv %MDR %B 

map mv_mdr_bp: 

0x34; 

// 

00110100 

= 

mv %MDR %BP 

map mv_mdr_sp: 

0x35; 

// 

00110101 

= 

mv %MDR %SP 

map op_error: 

0x3 6; 

// 

00110110 

= 

mv %MDR %MDR not valid 

map mv_mdr_f1: 

0x37; 

// 

00110111 

= 

mv %MDR %FL 

map mv_fl_i: 

0x38; 

// 

00111000 

= 

mv %FL %I 

map mv_fl_j: 

0x3 9; 

// 

00111001 

= 

mv %FL %J 

map mv_fl_a: 

0x3A; 

// 

00111010 

= 

mv %FL %A 

map mv_fl_b: 

0x3B; 

// 

00111011 

= 

mv %FL %B 

map mv_fl_bp: 

0x3C; 

// 

00111100 

= 

mv %FL %BP 

map mv_fl_sp: 

0x3D; 

// 

00111101 

= 

mv %FL %SP 

map mv_fl_mdr: 

0x3E; 

// 

00111110 

= 

mv %FL %MDR 

map op_error: 

0x3F; 

// 

00111111 

= 

mv %FL %FL not valid 

+0[7:0]=0x00; 






operands { 






%1,%2 = { +0 [5:3] = 

}; 

%1; +0 [2:0]=%2 

r 

}; 

}; 

op load8 { 


// 

010001.. 

— 

load8 

map load8_i: 

0x4 4; 

// 

01000100 

= 

load8 %I 

map load8_j: 

0x4 5; 

// 

01000101 

= 

load8 %J 

map load8: 

0x4 6; 

// 

01000110 

= 

load8 # . . . 

map op_error: 

0x4 7; 

// 

01000111 

= 

not valid 

+0[7:0]=0x44; 






operands { 






(%1) = { +0[1 

] = 0; 

+ 0 [0] 

=%1; }; 



#1 = { +0[1]= 

}; 

1; +0[0]=0 

; +1=#1 [ 7 

: C 

>]; +2=#1[15:8]; }; 

}; 

op loadl6 { 


// 

010010.. 

— 

loadl6 

map loadl6_i: 

0x4 8; 

// 

01001000 

= 

loadl6 %I 

map loadl6_j: 

0x4 9; 

// 

01001001 


loadl6 %J 

map loadl6: 

0x4A; 

// 

01001010 


loadl6 #... 






Version "C": 16-bit little-endian 


111 


map 

op_error: 

0x4B; 

+ 0 [7 

:0]=0x48; 


operands { 


(% 

1) = { +0[1 

] = 0; 

#1 

= { +0 [1] = 

1; +0 

}; 



> sto 

re8 { 


map 

store8_i: 

0x4C; 

map 

store8_j: 

0x4D; 

map 

store8: 

0x4E; 

map 

op_error: 

0x4F; 

+ 0 [7 

:0]=0x4C; 


operands { 


(% 

1) = { +0[1 

] = 0 ; 

#1 

= { +0 [1] = 

1; +0 

}; 



) sto 

rel6 { 


map 

storel6_i: 

0x50; 

map 

storel6_j: 

0x51; 

map 

storel6: 

0x52 ; 

map 

op_error: 

0x53; 

+ 0 [7 

:0]=0x50; 


operands { 


(% 

1) = { +0[1 

] = 0 ; 

#1 

= { +0 [1] = 

1; +0 

}; 



O 

00 

{ 


map 

cp8_ij: 

0x54; 

map 

cp8_ji: 

0x55; 

+ 0 [7 

:0]=0x54; 


operands { 


<% 

1) = { +0[0 

] =%1; 

}; 




= not valid 


0]; +2=#1[15:8]; }; 


}; 


// 010011 .. 
// 01001100 
// 01001101 
// 01001110 
// 01001111 


store8 
store8 %I 
store8 %J 
store8 #. . . 
not valid 


}; 


// 010100 .. 
// 01010000 
// 01010001 
// 01010010 
// 01010011 


0]; +2=#1[15:8]; }; 


storel6 
store16 %I 
store16 %J 
storel6 #. . . 
not valid 


0]; +2=#1[15:8]; }; 


}; 


// 0101010 . = 


cp8 

cp8 %I 
cp8 %J 



718 


Version "C": 16-bit little-endian 


}; 


op cpl6 { 


// 

map cpl6_ij: 

0x5 6; 

// 

map cpl6_ji: 

0x57; 

// 

+0[7:0]=0x56; 
operands { 

(%1) = { +0[0 

] =%1; 

}; 

}; 

}; 

op return { 


// 

map return: 

0x58; 

// 

+0[7:0]=0x58; 
operands op 0; 

}; 

op call { 


// 

map call: 

0x5 9; 

// 

map call_i: 

0x5A; 

// 

map call_j: 

0x5B; 

// 

+0[7:0]=0x58; 
operands { 

#1 = { +0[1]= 

0; +0 

[0] =: 

<%1) = { +0 [1 

] =i; 

+o [o; 

}; 

}; 

op int { 
map int: 

0x5C; 

// 


+ 0 [7:0]=0x5C; 
operands op_8; 

}; 

op iret { 

map iret: 0x5D; // 

+ 0 [7:0]=0x5D; 
operands op_0; 


0101011. = cpl6 
01010110 = cpl6 %I 
01010111 = cp!6 %J 


010110 .. 

01011000 = return 


010110 .. 

01011001 = call #. . . 
01011010 = call %I 
01011011 = call %J 


; +1 = #1[7:0]; +2=#1[15:8]; 

=%i; }; 


01011100 = int #... 


01011101 = iret 


}; 


}; 

op cleari { 

map cleari: 0x5E; // 01011110 = clear interrupt flag 



Version "C": 16-bit little-endian 


719 


+0[7:0]=0x5E; 
operands op_0; 

}; 

op seti { 

map seti: 0x5F; 

+0[7:0]=0x5F; 
operands op_0; 

}; 

op ivtl { 

map ivtl: 0x60; 

+0[7:0]=0x60; 
operands op_16; 

}; 

op jump { 

map jump: 0x61; 

+0[7:0]=0x61; 
operands op_16; 

}; 

op jump8c { 

map jump8c: 0x62; 

+0[7:0]=0x62; 
operands op_16; 

}; 

op jump8nc { 

map jump8nc: 0x63; 

+0[7:0]=0x63; 
operands op_16; 

}; 

op jump8z { 

map jump8z: 0x64; 

+0[7:0]=0x64; 
operands op_16; 

}; 

op jump8nz { 

map jump8nz: 0x65; 

+ 0 [7:0]=0x65; 


// 01011111 = set interrupt flag 


// 01100000 = load IVT location 


// 01100001 = jump #... 


// 01100010 = jump8c #... 


// 01100011 = jump8nc #... 


// 01100100 = jump8z #... 


// 01100101 = jump8nz #... 



720 


Version 


'C 


operands op_16; 

}; 

op jump8o { 

map jump8o: 0x66; 

+0[7:0]=0x66; 
operands op_16; 

}; 

op jump8no { 

map jump8no: 0x67; 

+0[7:0]=0x67; 
operands op_16; 

}; 

op jump8n { 

map jump8n: 0x68; 

+0[7:0]=0x66; 
operands op_16; 

}; 

op jump8nn { 


// 01100110 = jump8o #. 


// 01100111 = jump8no #. 


// 01101000 = jump8n #. 


map 

jump8nn: 

0x69; 

// 

01101001 

= 

jump8nn #. . 

map 

op_error: 

0x6A; 

// 

01101010 

= 

not 

valid 

map 

op_error: 

0x6B; 

// 

01101011 

= 

not 

valid 

map 

op_error: 

0 x 6 C; 

// 

01101100 

= 

not 

valid 

map 

op_error: 

0x6D; 

// 

01101101 

= 

not 

valid 

map 

op_error: 

0x6E; 

// 

01101110 

= 

not 

valid 

map 

op_error: 

0x6F; 

// 

01101111 

= 

not 

valid 

map 

op_error: 

0x7 0; 

// 

01110000 

= 

not 

valid 

map 

op_error: 

0x71; 

// 

01110001 

= 

not 

valid 


+0[7:0]=0x67; 
operands op_16; 


}; 

op jumpl6c { 
map jump16c: 

+0[7:0]=0x72; 
operands op_16; 

}; 

op jumpl6nc { 


0x72; // 01110010 = jump!6c #. 


: 16-bit little-endian 




Version "C": 16-bit little-endian 


721 


map jumpl6nc: 0x73; 
+0[7:0]=0x73; 
operands op_16; 

}; 

op jumpl6z { 

map jumpl6z: 0x74; 

+0[7:0]=0x74; 
operands op_16; 

}; 

op jumpl6nz { 

map jumpl6nz: 0x75; 
+0[7:0]=0x75; 
operands op_16; 

}; 

op jumpl6o { 

map jumpl6o: 0x76; 

+0[7:0]=0x76; 
operands op_16; 

}; 

op jumpl6no { 

map jumpl6no: 0x77; 
+0[7:0]=0x77; 
operands op_16; 

}; 

op jumpl6n { 

map jumpl6n: 0x78; 

+0[7:0]=0x76; 
operands op_16; 


// 01110011 = jumpl6nc #... 


// 01110100 = jumpl6z #... 


// 01110101 = jump!6nz #... 


// 01110110 = jumpl6o #... 


// 01110111 = jumpl6no #... 


// 01111000 = jumpl6n #... 


}; 

op jumpl6nn { 


map 

jumpl6nn: 

0x7 9; 

// 

01111001 

= 

jumpl6 #. . . 

map 

op_error: 

0x7A; 

// 

01111010 

= 

not 

valid 

map 

op_error: 

0x7B; 

// 

01111011 

= 

not 

valid 

map 

op_error: 

0x7C; 

// 

01111100 

= 

not 

valid 

map 

op_error: 

0x7D; 

// 

01111101 

= 

not 

valid 

map 

op_error: 

0x7E; 

// 

01111110 

= 

not 

valid 



722 


Version "C": 16-bit little-endian 


map op_error: 

0x7F; 

// 

01111111 

= 

not valid 

+0[7:0]=0x77; 






operands op 16 

}; 

op push8 { 

r 

// 

10000... 


push8 

map push8_i: 

0x80; 

// 

10000000 

= 

push8 %I 

map push8_j: 

0x81; 

// 

10000001 

= 

push8 %J 

map push8_a: 

0x82; 

// 

10000010 

= 

push8 %A 

map push8_b: 

0x83; 

// 

10000011 

= 

push8 %B 

map push8_bp: 

0x84; 

// 

10000100 

= 

push8 %BP 

map op_error: 

0x85; 

// 

10000101 

= 

push8 %SP not valid 

map push8_mdr: 

0x8 6; 

// 

10000110 

= 

push8 %MDR 

map push8_fl: 

+0[7:0]=0x80; 

0x87; 

// 

10000111 

— 

push8 %FL 

operands { 

%1 = { +0[2: 

}; 

0]=%1; 

}; 




}; 

op pop8 { 


// 

10001... 

__ 

pop8 

map pop8_i: 

0x8 8; 

// 

10001000 

= 

pop8 %I 

map pop8_j: 

0x8 9; 

// 

10001001 


pop8 %J 

map pop8_a: 

0x8A; 

// 

10001010 

= 

pop8 %A 

map pop8_b: 

0x8B; 

// 

10001011 

= 

pop8 %B 

map pop8_bp: 

0x8C; 

// 

10001100 

= 

pop8 %BP 

map op_error: 

0x8D; 

// 

10001101 


pop8 %SP not valid 

map pop8_mdr: 

0 x 8 E ; 

// 

10001110 

= 

pop8 %MDR 

map pop8_fl: 

+0[7:0]=0x88; 

0x8F; 

// 

10001111 


pop8 %FL 

operands { 

%1 = { +0[2: 

}; 

0]=%1; 

}; 




}; 

op pushl6 { 


// 

10010... 


pushl6 

map pushl6_i: 

0x90; 

// 

10010000 

= 

pushl6 %I 

map pushl6_j: 

0x91; 

// 

10010001 

= 

pushl6 %J 

map pushl6_a: 

0x92; 

// 

10010010 


pushl6 %A 







Version "C": 16-bit little-endian 


723 


}; 


map pushl6_b: 0x93; // 

map pushl6_bp: 0x94; // 

map op_error: 0x95; // 

map pushl6_mdr: 0x96; // 

map pushl6_fl: 0x97; // 

+0[7:0]=0x90; 
operands { 

%1 = { + 0 [ 2 : 0 ]=% 1 ; }; 

}; 


10010011 = pushl6 %B 
10010100 = pushl6 %BP 
10010101 = pushl6 %SP not valid 
10010110 = pushl6 %MDR 
10010111 = pushl6 %FL 


op popl6 { 


// 

10011... 

= 

popl 6 


map 

popl6_i: 

0x98; 

// 

10011000 

= 

popl 6 

%I 

map 

popl6_j: 

0x99; 

// 

10011001 

= 

popl 6 

%J 

map 

popl6_a: 

0x9A; 

// 

10011010 

= 

popl 6 

%A 

map 

popl6_b: 

0x9B; 

// 

10011011 

= 

popl 6 

%B 

map 

popl6_bp: 

0 x 9 C; 

// 

10011100 

= 

popl 6 

%BP 

map 

op_error: 

0x9D; 

// 

10011101 

= 

popl 6 

%SP not valid 

map 

popl6_mdr: 

0x9E; 

// 

10011110 

= 

popl 6 

%MDR 

map 

popl6_f1: 

0x9F; 

// 

10011111 

= 

popl 6 

%FL 


+0[7:0]=0x98; 
operands { 

%1 = { + 0 [ 2 : 0 ]=% 1 ; }; 

}; 


}; 

op c8tol6u { 
map c8tol6u: 

+0[7:0]=0xA0; 
operands op_0; 

}; 

op c8tol6s { 
map c8tol6s: 

+0[7:0]=0xAl; 
operands op_0; 

}; 

op equal { 
map equal: 


OxAO; // 10100000 


OxAl; // 10100001 


0xA2; // 10100010 






724 


Version "C": 16-bit little-endian 


+0[7:0]=0xA2; 
operands op_0; 

}; 

op not { 
map not: 

+0[7:0]=0xA3; 
operands op_0; 

}; 

op and { 
map and: 

+0[7:0]=0xA4; 
operands op_0; 

}; 

op nand { 
map nand: 

+0[7:0]=0xA5; 
operands op_0; 

}; 

op or { 
map or: 

+0[7:0]=0xA6; 
operands op_0; 

}; 

op nor { 
map nor: 

+0[7:0]=0xA7; 
operands op_0; 

}; 

op xor { 
map xor: 

+0[7:0]=0xA8; 
operands op_0; 

}; 

op nxor { 
map nxor: 

+0[7:0]=0xA9; 


0xA3; // 10100011 


0xA4; // 10100100 


0xA5; // 10100101 


0xA6; // 10100110 


0xA7; // 10100111 


0xA8; // 10101000 


0xA9; // 10101001 



Version "C": 16-bit little-endian 


725 


operands op_0; 

}; 

op add { 
map add: 

+0[7:0]=0xAA; 
operands op_0; 

}; 

op sub { 
map sub: 

+0[7:0]=0xAB; 
operands op_0; 

}; 

op addc8 { 
map addc8: 

+ 0 [ 7:0]=0xAC; 
operands op_0; 

}; 

op subb8 { 
map subb8: 

+0[7:0]=0xAD; 
operands op_0; 

}; 

op addcl6 { 
map addcl6: 

+0[7:0]=0xAE; 
operands op_0; 

}; 

op subbl6 { 
map subbl6: 

+0[7:0]=0xAF; 
operands op_0; 

}; 

op lshl8 { 
map lshl8: 

+0[7:0]=0xB0; 
operands op_0; 


OxAA; // 10101010 


0 xAB; // 10101011 


OxAC; // 10101100 


OxAD; // 10101101 


OxAE; // 10101110 


0 xAF; // 10101111 


OxBO; // 10110000 



726 


Version "C": 16-bit little-endian 


}; 

op lshr8 { 
map lshr8: 

+0[7:0]=0xBl; 
operands op_0; 

}; 

op ashl8 { 
map ashl8: 

+0[7:0]=0xB2; 
operands op_0; 

}; 

op ashr8 { 
map ashr8: 

+0[7:0]=0xB3; 
operands op_0; 

}; 

op rotcl8 { 
map rotcl8: 

+0[7:0]=0xB4; 
operands op_0; 

}; 

op rotcr8 { 
map rotcr8: 

+ 0 [ 7:0]=0xB5; 
operands op_0; 

}; 

op rotl8 { 
map rotl8: 

+ 0 [7:0]=0xB6; 
operands op_0; 

}; 

op rotr8 { 
map rotr8: 

+0[7:0]=0xB7; 
operands op_0; 

}; 


OxBl; // 10110001 


0xB2; // 10110010 


0 xB 3; // 10110011 


0xB4; // 10110100 


0 xB 5; // 10110101 


0xB6; // 10110110 


0 xB 7; // 10110111 



Version "C": 16-bit little-endian 


727 


op lshll6 { 
map lshll6: 

+0[7:0]=0xB8; 
operands op_0; 

}; 

op lshrl6 { 
map lshrl6: 

+0[7:0]=0xB9; 
operands op_0; 

}; 

op ashll6 { 
map ashll6: 

+0[7:0]=0xBA; 
operands op_0; 

}; 

op ashrl6 { 
map ashrl6: 

+0[7:0]=0xBB; 
operands op_0; 

}; 

op rotcll6 { 
map rotcll6: 

+0[7:0]=0xBC; 
operands op_0; 

}; 

op rotcrl6 { 
map rotcrl6: 

+0[7:0]=0xBD; 
operands op_0; 

}; 

op rotll6 { 
map rotll6: 

+0[7:0]=0xBE; 
operands op_0; 

}; 

op rotrl6 { 


0xB8; // 10111000 


0xB9; // 10111001 


OxBA; // 10111010 


OxBB; // 10111011 


OxBC; // 10111100 


OxBD; // 10111101 


OxBE; // 10111110 



728 


Version "C": 16-bit little-endian 


map rotrl6: OxBF; // 10111111 

+ 0 [ 7:0]=0xBF; 
operands op_0; 

}; 

op in { 

map in: OxCO; // 11000000 

+0[7:0]=0xC0; 
operands op_8; 

}; 

op out { 

map out: OxCl; // 11000001 

+0[7:0]=0xCl; 
operands op_8; 

}; 

op ifack_jump { 

map ifack_jump: 0xC2; // 11000010 

map op_error: 0xC3; // 11000011 

+0[7:0]=0xC2; 
operands { 

#1,#2 = { +1 = #1 [ 7:0]; +2=#1[7:0]; +3=#2[17:8]; }; 

}; 

}; 

op clearc { 

map clearc: 0xC4; // 11000100 

+0[7:0]=0xC4; 
operands op_0; 

}; 

op setc { 

map setc: 0xC5; // 11000101 

+0[7:0]=0xC5; 
operands op_0; 

}; 

op cmp { 

map cmp: 0xC6; // 11000110 

+0[7:0]=0xC6; 
operands op_0; 



Version "C": 16-bit little-endian 


729 


}; 

op test { 







map test: 

0xC7; 

// 

11000111 




+0[7:0]=0xC7; 







operands op_0; 

j. 







J r 

op imrl { 







map imrl: 

0xC8; 

// 

11001000 

// 

IMR 

load 

map op_error: 

0xC9; 

// 

11001001 




map op_error: 

OxCA; 

// 

11001010 




map op_error: 

OxCB; 

// 

11001011 




map op_error: 

OxCC; 

// 

11001100 




map op_error: 

OxCD; 

// 

11001101 




map op_error: 

OxCE; 

// 

11001110 




map op_error: 

OxCF; 

// 

11001111 




+0[7:0]=0xC8; 







operands op_8; 

j; 







J ' 

op inc { 







map inc_i: 

0x00; 

// 

11010000 

// 

inc 

%I 

map inc_j: 

OxDl; 

// 

11010001 

// 

inc 

%J 

map inc_a: 

0 xD 2; 

// 

11010010 

// 

inc 

%A 

map inc_b: 

0 xD 3; 

// 

11010011 

// 

inc 

%B 

map inc_bp: 

0 xD 4; 

// 

11010100 

// 

inc 

%BP 

map inc_sp: 

0 xD 5; 

// 

11010101 

// 

inc 

%SP 

map inc_mdr: 

0xD6; 

// 

11010110 

// 

inc 

%MDR 

map inc_f1: 

0xD7; 

// 

11010111 

// 

inc 

%FL 

+0[7:0]=0xD0; 







operands { 







%1 = { +0[2: 

}; 

0]=%1; 

}; 





}; 

op dec { 







map dec_i: 

0 xD 8; 

// 

11011000 

// 

dec 

%I 

map dec_j: 

0 xD 9; 

// 

11011001 

// 

dec 

%J 

map dec_a: 

OxDA; 

// 

11011010 

// 

dec 

%A 





730 


Version "C": 16-bit little-endian 


map 

dec_b : 

OxDB; 

// 

11011011 

// 

dec 

%B 

map 

dec_bp : 

OxDC; 

// 

11011100 

// 

dec 

%BP 

map 

dec_sp : 

OxDD; 

// 

11011101 

// 

dec 

%SP 

map 

dec_mdr : 

OxDE; 

// 

11011110 

// 

dec 

%MDR 

map 

dec_f 1 : 

OxDF; 

// 

11011111 

// 

dec 

%FL 

map 

op_error: 

OxEO; 

// 

11100001 




map 

op_error: 

OxEl ; 

// 

11100010 




map 

op_error : 

0 xE 2 ; 

// 

11100011 




map 

op_error : 

0 xE 4 ; 

// 

11100100 




map 

op_error : 

0 xE 5 ; 

// 

11100101 




map 

op_error : 

0 xE 6 ; 

// 

11100110 




map 

op_error : 

0 xE 7 ; 

// 

11100111 




map 

op_error : 

0 xE 8 ; 

// 

11101000 




map 

op_error : 

OxE 9 ; 

// 

11101001 




map 

op_error : 

OxEA; 

// 

11101010 




map 

op_error : 

OxEB; 

// 

11101011 




map 

op_error : 

OxEC; 

// 

11101100 




map 

op_error: 

OxED; 

// 

11101101 




map 

op_error: 

OxEE; 

// 

11101110 




map 

op_error: 

OxEF; 

// 

11101111 




map 

op_error: 

OxFO; 

// 

11110001 




map 

op_error: 

OxFl; 

// 

11110010 




map 

op_error : 

0 xF 2 ; 

// 

11110011 




map 

op_error : 

0 xF 4 ; 

// 

11110100 




map 

op_error : 

0 xF 5 ; 

// 

11110101 




map 

op_error : 

0xF6; 

// 

11110110 




map 

op_error : 

0xF7 ; 

// 

11110111 




map 

op_error : 

0xF8; 

// 

11111000 




map 

op_error : 

OxF 9 ; 

// 

11111001 




map 

op_error : 

OxFA; 

// 

11111010 




map 

op_error : 

OxFB ; 

// 

11111011 




map 

op_error : 

OxFC; 

// 

11111100 




map 

op_error: 

OxFD; 

// 

11111101 




map 

op_error: 

OxFE; 

// 

11111110 




+ 0 [1 

' :0]=0xD8; 







operands { 









Version "C": 16-bit little-endian 


731 



Table 11.38. Macrocode syntax. 


Macrocode syntax 

Binary 

opcode 

Description 

nop 

00000000 

Not operate: does not do 
anything. 

mv %src, %dst 

00 sssddd 

Copy the src register con¬ 
tent inside the dst regis¬ 
ter. Allowed registers are: 
/, 7, A, B , BP , SP, 
MDR, FL. The opcode 
OOOOOOOO 2 remains for the 
nop instruction, because it 
would represent the copy 
of register A into the same 
register A . 









732 


Version "C": 16-bit little-endian 


Macrocode syntax 


load8 (%I 


%J) 


load8 address 


loadl6 (%I 


%J) 


load 16 address 


Binary 

opcode 


0100010 / 

01000110 

0100100 / 

01001010 


Description 

Load inside the MDR reg¬ 
ister an 8-bit or 16-bit 
value from the memory. 
The argument might be an 
index register (/ or J) and 
in that case the bit / is used 
to distinguish the register 
inside the opcode; other¬ 
wise, the argument can be 
directly the memory ad¬ 
dress and the last two bits 
of the opcode are equal to 


store8 



store8 address 


storel6 (%I 
load 16 address 


J) 


%J) 


0100110 / 

01001110 

0101000 / 

01010010 


10 2 . _ 

Store in memory (eight or 

sixteen bits), at the address 
specified by the argument, 
the value contained inside 
the MDR register. If the 
argument is an index reg¬ 
ister (/ or /), then the 
bit / is used to distinguish 
the register inside the op¬ 
code; otherwise, the argu¬ 
ment can be directly the 
memory address and the 
last two bits of the opcode 
are equal to 10 2 . 




Version "C": 16-bit little-endian 


733 


Macrocode syntax 

Binary 

opcode 

Description 

cp8 (%I 

cpl6 (%I 

%J) 

%J) 

01010105 

01010115 

Copy from RAM memory 
to RAM memory eight or 
sixteen bits, starting from 
the position represented by 
the content of the index 
register specified, to the 
position represented by the 
content of the other index 
register. 

return 

call %ref 

call (%I 

%J) 

01011000 

01011001 

0101101/ 

Return from a call to a 
routine. The bit i repre¬ 
sents an index register (/ 
or /). The call instruc¬ 
tion pushes the register PC 
onto the stack, whereas 
the return instruction re¬ 
stores the register PC from 
the stack. 




734 


Version "C": 16-bit little-endian 


Macrocode syntax 

Binary 

opcode 

Description 

int n-interrupt 

iret 

01011100 

01011101 

Interrupt call and interrupt 
return; the size of the ar¬ 
gument n.interrupt is 8- 
bit, but can be only a 
value from zero to six¬ 
teen. When the int in¬ 
struction is encountered, 
the registers FL and PC 
are saved inside the stack 
and then the IRQ en¬ 
able flag is zeroed; when 
an iret instruction is 
encountered, the registers 
PC and FL are restored 
from the stack. 

cleari 

seti 

01011110 

01011111 

Reset or set the hardware 
interrupts flags, contained 
inside the FL register. 

ivtl #ref 

01100000 

Load the IVT: interrupt 
vector table. The argument 
is the interrupt vector table 
start address in memory. 

jump %ref 

01100001 

Jump to the address speci¬ 
fied. 




Version "C": 16-bit little-endian 


735 


Macrocode syntax 

Binary 

opcode 

Description 

jump8c %ref 


Jump to the instruction lo- 

01100010 

-L 

cated at the specified ad¬ 
dress if: 

jump8nc %ref 

01100011 

the 8-bit carry flag is ac¬ 
tive, 

jump8z $ref 

01100100 

the 8-bit carry flag is not 
active, 

jump8nz #ref 

01100101 

the 8-bit zero flag is active, 
the 8-bit zero flag is not 

jump8o #ref 

01100110 

active, 

the 8-bit overflow flag is 

jump8no #ref 

01100111 

active, 

the 8-bit overflow flag is 

jump8n #ref 

01101000 

not active, 

the 8-bit sign flag is active, 

jump8nn $ref 

01101001 

the 8-bit sign flag is not ac¬ 
tive. 




736 


Version "C": 16-bit little-endian 


Macrocode syntax 

j ump16c #ref 
jumpl6nc #ref 
j ump16 z #ref 
jumpl6nz tref 
j ump16 o %ref 
jumpl6no %ref 
jumpl6n #ref 
jumpl6nn tref 


push 8 % register 
pop8 %register 


Binary 

opcode 

01110010 

01110011 

01110100 

01110101 

01110110 

01110111 

01111000 

01111001 


10 00 0m* 

lOOOlrrr 


Description 

Jump to the instruction lo¬ 
cated at the specified ad¬ 
dress if: 

the 16-bit carry flag is ac¬ 
tive, 

the 16-bit carry flag is not 
active, 

the 16-bit zero flag is ac¬ 
tive, 

the 16-bit zero flag is not 
active, 

the 16-bit overflow flag is 
active, 

the 16-bit overflow flag is 
not active, 

the 16-bit sign flag is ac¬ 
tive, 

the 16-bit sign flag is not 

active. _ 

Push on top of the stack 

the 8-bit content of the 
specified register, other¬ 
wise restore the specified 
register removing the last 
8-bit value from the top 
of the stack. Please notice 
that the push and pop of 
the SP register is not valid. 




Version "C": 16-bit little-endian 


737 


Macrocode syntax 

Binary 

opcode 

Description 

p u s h 16 % register 

pop 16 %register 

lOOlOrrr 

lOOllrrr 

Push on top of the stack 
the 16-bit content of the 
specified register, other¬ 
wise restore the specified 
register removing the last 
16-bit value from the top 
of the stack. Please notice 
that the push and pop of 
the SP register is not valid. 

c8tol6u 

c8tol6s 

10100000 

10100001 

Change the A value to a 8- 
bit unsigned or signed. 




738 


Version "C": 16-bit little-endian 


Macrocode syntax 

Binary 

opcode 

Description 

equal 

10100010 


not 

10100011 


and 

10100100 

Logical operation starting 

nand 

10100101 

from the values contained 
inside the registers A and 

or 

10100110 

B , placing the result back 
to the A register. 

nor 

10100111 


xor 

101001000 


nxor 

10101001 




Addition or subtraction: 
A+B or A-B. The previ¬ 

add 

10101010 

ous carry or borrow status 
is not taken into considera¬ 

sub 

10101011 

tion, but the result will up¬ 
date the new carry or bor¬ 
row status. The result is 
saved inside the A register. 




Version "C": 16-bit little-endian 


739 


Macrocode syntax 

Binary 

opcode 

Description 

addc8 

10101100 

Addition or subtraction 
with previous carry or 

subb8 

10101101 

borrow: A+B+carry or 
A-B-borrow . The result 

addcl6 

10101110 

is saved inside the A reg¬ 
ister. The number eight or 

subbl6 

10101111 

sixteen is used to select the 
input carry or borrow. 

lshl8 

10110000 


lshr8 

10110001 


ashl8 

10110010 

Bit shift and rotation with 

ashr8 

10110011 

8-bit size, over the origi¬ 
nal A register value, plac¬ 

rotcl8 

10110100 

ing the result on the same 
A register. 

rotcr8 

10110101 


rotl8 

10110110 


rotr8 

10110111 





Version "C": 16-bit little-endian 


/ 4U 


Macrocode syntax 

Binary 

opcode 

Description 

lshll6 

10111000 


lshrl6 

10111001 


ashll6 

10111010 

Bit shift and rotation with 

ashrl6 

10111011 

16-bit size, over the origi¬ 
nal A register value, plac¬ 

rotcll6 

10111100 

ing the result on the same 
A register. 

rotcrl6 

10111101 


rotll6 

10111110 


rotrl6 

10111111 





Version "C": 16-bit little-endian 


741 


Macrocode syntax 

Binary 

opcode 

Description 



Read or write a value at 
the I/O address specified. 
The I/O address is a 8- 



bit number. For is_ack it 

in io 

11000000 

is checked the confirma¬ 
tion (acknowledge) from 

out io 

11000001 

the device and, if there is 
one, the condition is ver- 

ifack jump io, #ref 

11000010 

ified and a jump is done 



to the address specified 
as the last argument. Cur¬ 
rently, only the screen de¬ 
vice can be used with the 
ifack_jump instruction. 

clearc 

11000100 

Clear or set the carry flags 

setc 

11000101 

inside the FL register. 



Compare registers A and 

cmp 

11000110 

B , simulating a subtrac¬ 
tion or the AND, just to 

test 

11000111 

update the flags inside the 
FL register. 




742 


Version "C": 16-bit little-endian 


Macrocode syntax 

Binary 

opcode 

Description 

imrl mask 

11001000 

Load the hardware inter¬ 
rupt mask: the active bits 
are related to interrupts to 
be enabled. The argument 
is a 8-bit number, but only 
the least significant four 
bits are used (there are 
only four hardware inter¬ 
rupts). 

inc %register 

dec %register 

11010m* 

HOllrrr 

One unit increment or 
decrement, to the specified 
register, which is written at 
the last three bits inside the 
opcode. 

stop 

11111111 

CPU halt, locking the 
clock signal. 


11.10 Microcode 

Listing 11.39. Fields of the microcode word, for TKGate. 

field Ctrl [1:0] = {nop=0, stop=l, load=2}; 

field pc[10:2] = {br=l, bw=2, aux=4, low=8, high=16, 

pl=32, p2=64, ml=128, m2=256}; 
field sel[15:ll] = {if_carry_8=l, if_not_carry_8=3, 

if_zero_8=5, if_not_zero_8=7, 
if_negative_8=9, if_not_negative_8=ll, 
if_overflow_8=13, if_not_overflow_8=15, 
if_carry_l6=1 , if_not_carry_l6=3, 
if_zero_16=5, if_not_zero_l6=7, 
if_negative_l6=9, if_not_negative_l6=11, 










Version "C": 16-bit little-endian 


74 J 


if_overflow_l6=13, if_not_overflow_l6=15}; 


field 

mdr[24:16] 

= 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

i [33:25] 

— 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

j [42:34] 

— 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

ram[47:43] 

= 

{br=l, bw=2, aux=4, p=0, i=8, j=16, s=24}; 

field 

ivt[50:48] 

= 

{br=l, bw=2, inta=0, intb=4}; 

field 

ir[59:51] 

— 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

bus[77:60] 

= 

{bw=0xl0000, aux=0x20000}; 

field 

irq[80:78] 

= 

{br=l, bw=2, done=4}; 

field 

sp [89:81] 

— 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

bp[98:90] 

— 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

b[107:99] 

— 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

fl[116:108] 

— 

{br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

field 

alu [127:117] 

— 

{bw=l, aux=2, sign=4, rank8=0, rankl6=8, 
a=0, and=16, or=32, xor=48, 


field a[136:128] 
field ioa [145:137 


nxor=64, nor=80, nand=96, not=112, 
add=256, sub=228, addc=320, subb=352, 
lshl=512, lshr=528, ashl=484, ashr=560, 
rotcl=576, rotcr=592, 
rotl=768, rotr=784, 

clearc=1024, clearz=1040, clearn=1056, 
clearo=1072, cleari=1088, 
setc=1152, setz=1168, setn=1184, 
seto=1200, seti=1216}; 

= {br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 

= {br=l, bw=2, aux=4, low=8, high=16, 
pl=32, p2=64, ml=128, m2=256}; 




744 


Version "C": 16-bit little-endian 


field ioc[149:146] = {br=l, bw=2, req=4, isack=8}; 


Listing 11.40. Microcode. 


begin microcode @ 0 

// 

// fetch: 

// IR <— RAM[pc++]; load; 

// 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

// 


nop: 

// fetch: 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
op_error: 

// INT 0 


// push FL 

sp=m2; 

ram=br ram=s fl=bw fl=low sp=pl; 
ram=br ram=s fl=bw fl=high sp=ml; 

// reset interrupt enable flag 

fl=br fl=aux alu=cleari; 

// push PC 

sp=m2; 

ram=br ram=s pc=bw pc=low sp=pl; 
ram=br ram=s pc=bw pc=high sp=ml; 

// push I 

sp=m2; 

ram=br ram=s i=bw i=low sp=pl; 
ram=br ram=s i=bw i=high sp=ml; 

// 


// SP <— (SP - 2) 

// RAM[sp++] <- FL[7:0]; 
// RAM[sp—] <- FL[15:8]; 


// SP <— (SP ~ 2) 

// RAM[sp++] <- PC[7:0]; 
// RAM[sp—] <- PC[15:8]; 

// SP <— (SP ~ 2) 

// RAM[sp++] <- I[7:0]; 
// RAM[sp—] <- I[15:8]; 


i=br ivt=bw ivt=intb 
pc=br pc=low ram=bw 
pc=br pc=high ram=bw 

// pop I 


bus=bw bus=aux 
ram=i i=pl; 
ram=i i=ml; 


bus = 0; // J <- IVT <- 0; 

// PC[7:0] < — RAM[i++] 

// PC [15: 7] < — RAM[i—] 


i=br i=low ram=bw ram=s sp=pl; // I[7:0] <— RAM[sp++]; 

i=br i=high ram=bw ram=s sp=pl; // I[15:0] <— RAM[sp++]; 

// fetch 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
mv_i_j : 


j=br i=bw // J <- I, fetch; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 




Version "C": 16-bit little-endian 


745 


mv_i_a: 

a=br i=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

3 

li 

// A <- I, fetch; 

pc=pl ctrl=load; 

mv_i_b: 

b=br i=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// B <- I, fetch; 

pc=pl ctrl=load; 

mv_i_bp: 

bp=br i=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// BP <- I, fetch; 

pc=pl ctrl=load; 

mv_i_sp: 

sp=br i=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// SP <- I, fetch; 

pc=pl ctrl=load; 

mv_i_mdr: 

mdr=br i=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

B 

li 

// MDR <- J, fetch; 

pc=pl ctrl=load; 

1: 

fl=br i=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// FL <- J, fetch; 

pc=pl ctrl=load; 

mv_ j_i : 

i=br j=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// I <- J , fetch; 

pc=pl ctrl=load; 

mv_j_a: 

a=br j=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// A <- J, fetch; 

pc=pl ctrl=load; 

mv_j_b: 

b=br j=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// B <- J , fetch; 

pc=pl ctrl=load; 

mv_j_bp: 

bp=br j=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// BP <- J , fetch; 

pc=pl ctrl=load; 

mv_j_sp: 

sp=br j=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// SP <- J , fetch; 

pc=pl ctrl=load; 

mv_j_mdr: 

mdr=br j=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// MDR <- J , fetch; 

pc=pl ctrl=load; 

mv_j_f1: 

fl=br j=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// FL <- J , fetch; 

pc=pl ctrl=load; 

mv_a_i: 

i=br a=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// I <- A, fetch; 

pc=pl ctrl=load; 



746 


Version "C": 16-bit little-endian 


mv_a_ j : 

j=br a=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

3 

li 

// J <- A, fetch; 

pc=pl ctrl=load; 

mv_a_b: 

b=br a=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// B <- A, fetch; 

pc=pl ctrl=load; 

mv_a_bp: 

bp=br a=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// BP <- A, fetch; 

pc=pl ctrl=load; 

mv_a_sp: 

sp=br a=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// SP <- A, fetch; 

pc=pl ctrl=load; 

mv_a_mdr: 

mdr=br a=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

B 

li 

// MDR <- A, fetch; 

pc=pl ctrl=load; 

mv_a_f1: 

fl=br a=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// FL <- A, fetch; 

pc=pl ctrl=load; 

mv_b_i : 

i=br b=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// J <- B, fetch; 

pc=pl ctrl=load; 

mv_b_j: 

j =br b=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// J <- B, fetch; 

pc=pl ctrl=load; 

mv_b_a: 

a=br b=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// A <- B, fetch; 

pc=pl ctrl=load; 

mv_b_bp: 

bp=br b=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// BP <- B, fetch; 

pc=pl ctrl=load; 

mv_b_sp: 

sp=br b=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// SP <- B, fetch; 

pc=pl ctrl=load; 

mv_b_mdr: 

mdr=br b=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// MDR <- B, fetch; 

pc=pl ctrl=load; 

mv_b_f1: 

fl=br b=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// FL <- B, fetch; 

pc=pl ctrl=load; 

mv_bp_i: 

i=br bp=bw 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

// J <- BP, fetch; 

pc=pl ctrl=load; 



Version "C": 16-bit little-endian 


747 


mv_bp_ j : 

j=br bp=bw 




// J <- BP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

B 

li 

pc=pl ctrl=load; 

mv_bp_a : 

a=br bp=bw 




// A <- BP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_bp_b : 

b=br bp=bw 




// B <- BP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_bp_sp: 

sp=br bp=bw 




// SP <- BP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_bp_mdr: 

mdr=br bp=bw 




// MDR <- BP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

B 

li 

pc=pl ctrl=load; 

mv_bp_f 1: 

fl=br bp=bw 




// FL <- BP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_sp_i : 

i=br sp=bw 




// J <- SP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_sp_j : 

j =br sp=bw 




// J <- SP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_sp_a : 

a=br sp=bw 




// A <- SP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_sp_bp : 

bp=br sp=bw 




// BP <- SP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_sp_b: 

b=br sp=bw 




// B <- SP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_sp_mdr: 

mdr=br sp=bw 




// MDR <- SP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_sp_f1: 

fl=br sp=bw 




// FL <- SP, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_mdr_i: 





i=br mdr=bw 




// J <- MDR, fetch; 

ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 



748 


Version "C": 16-bit little-endian 


mv_ 

_mdr_j: 






j=br mdr=bw 




// J <- MDR, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

B 

li 

pc=pl ctrl=load; 

mv_ 

_mdr_bp: 






bp=br mdr=bw 




// BP <- MDR, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_mdr_sp: 






sp=br mdr=bw 




// SP <- MDR, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_mdr_b: 






b=br mdr=bw 




// B <- MDR, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_mdr_a: 






a=br mdr=bw 




// A <- MDR, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

n 

p 

B 

II 

pc=pl ctrl=load; 

mv_ 

_mdr_f1: 






fl=br mdr=bw 




// FL <- MDR, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_f l_i : 






i=br fl=bw 




// I <- FL, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 







j=br fl=bw 




// J <- FL, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_fl_a: 






a=br fl=bw 




// A <- FL, fetch; 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_fl_bp: 






bp=br fl=bw 




// BP <- FL, fetch 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_fl_sp: 






sp=br fl=bw 




// SP <- FL, fetch 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_fl_mdr: 






mdr=br fl=bw 




// MDR <- FL, fetch 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

mv_ 

_fl_b: 






fl=br b=bw 




// B <- FL, fetch 


ir=aux ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

load8_i: 






mdr=br ram=bw : 

ram=i; 



// MDR <- RAM[i]; 


ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; // fetch 



Version "C": 16-bit little-endian 


749 


load8_j: 

mdr=br ram=bw ram=j; 


// MDR <- RAM[j] ; 

ir=aux ir=br ram=aux ram=bw ram=p 

ts 

o 

II 

i— i 

ctrl=load; // fetch 

load8: 

i=br i=low ram=bw ram=p pc=pl; 


// I [7:0] <- RAM[pc++] ; 

i=br i=high ram=bw ram=p pc=pl; 


// I [15:8] <- RAM [pc++ ] ; 

mdr=br ram=bw ram=i; 


// MDR <- RAM[i] ; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

loadl6_i: 

mdr=br mdr=low ram=bw ram=i i=pl; 


// MDR[7:0] <- RAM[±++]; 

mdr=br mdr=high ram=bw ram=i i=ml; 


// MDR [ 15:8] <- RAM[i — ]; 

ir=aux ir=br ram=aux ram=bw ram=p 

ts 

o 

II 

1— i 

ctrl=load; // fetch 

loadl6_j: 

mdr=br mdr=low ram=bw ram=j j=pl; 


// MDR[7:0] <- RAM [ j++] ; 

mdr=br mdr=high ram=bw ram=j j=ml; 


// MDR [15:8] <- RAM[j —]; 

ir=aux ir=br ram=aux ram=bw ram=p 

ts 

o 

II 

1— i 

ctrl=load; // fetch 

loadl6: 

i=br i=low ram=bw ram=p pc=pl; 


// I [7:0] <- RAM[pc++ ]; 

i=br i=high ram=bw ram=p pc=pl; 


// I [15:8] <- RAM[pc++] ; 

mdr=br mdr=low ram=bw ram=i i=pl; 


// MDR[7:0] <- RAM[i++] ; 

mdr=br mdr=high ram=bw ram=i i=ml; 


// MDR [ 15:8] <- RAM[i —]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

store8_i: 

ram=br ram=i mdr=bw; 


// RAM[i ] <- MDR[7:0]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

store8_j: 

ram=br ram=j mdr=bw; 


// RAM[j] <- MDR[7:0]; 

ir=aux ir=br ram=aux ram=bw ram=p 

ts 

o 

II 

1— i 

ctrl=load; // fetch 

store8: 

i=br i=low ram=bw ram=p pc=pl; 


// I [7:0] <- RAM[pc++]; 

i=br i=high ram=bw ram=p pc=pl; 


// I [15:8] <- RAM[pc++] ; 

ram=br ram=i mdr=bw; 


// RAM[i ] <- MDR[7:0]; 

ir=aux ir=br ram=aux ram=bw ram=p 

ts 

o 

II 

ctrl=load; // fetch 

storel6_i: 

ram=br ram=i mdr=bw mdr=low i=pl; 


// RAM[i++ ] <- MDR[7:0]; 

ram=br ram=i mdr=bw mdr=high i=ml; 


// RAM[i —] <- MDR [15:8]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

storel6_j: 

ram=br ram=j mdr=bw mdr=low j=pl; 


// RAM[j++] <- MDR[7:0]; 

ram=br ram=j mdr=bw mdr=high j=ml; 


// RAM[j —] <- MDR [15:8]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

store!6: 



750 


Version "C": 16-bit little-endian 


i=br i=low ram=bw ram=p pc=pl; 

// I[7:0] <- 

■ RAM[pc++] ; 

i=br i=high ram=bw ram=p pc=pl; 

// I[15:8] < 

RAM[pc++] ; 

ram=br ram=i mdr=bw mdr=low i=pl; 

// RAM[i++] 

<- MDR[7:0]; 

ram=br ram=i mdr=bw mdr=high i=ml; 

// RAM[i—] 

<- MDR[15:8]; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

// fetch 

cp8_ij: 

mdr=br ram=bw ram=i i=pl; 

// MDR [7:0] 

<- RAM[i++] ; 

ram=br ram=j mdr=bw j=pl; 

// RAM[j++] 

<- MDR[7:0]; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

// fetch 

o 

00 

1 

l_1- 

H- 

mdr=br ram=bw ram=j j=pl; 

// MDR [7:0] 

<- RAM[j++]; 

ram=br ram=i mdr=bw i=pl; 

// RAM[i++] 

<- MDR[7:0]; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

// fetch 

cpl6_ij: 

mdr=br mdr=low ram=bw ram=i i=pl; 

// MDR [7:0] 

<- RAM[i++]; 

mdr=br mdr=high ram=bw ram=i i=pl; 

// MDR[15:8] 

<- RAM[i++]; 

ram=br ram=j mdr=bw mdr=low j=pl; 

// RAM[j++] 

<- MDR[7:0]; 

ram=br ram=j mdr=bw mdr=high j=pl; 

// RAM[j++] 

<- MDR [15:0]; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

// fetch 

cpl6_ji: 

mdr=br mdr=low ram=bw ram=j j=pl; 

// MDR [7:0] 

<- RAM[j++]; 

mdr=br mdr=high ram=bw ram=j j=pl; 

// MDR [ 15:8] 

<- RAM[j++] ; 

ram=br ram=i mdr=bw mdr=low i=pl; 

// RAM[i++] 

<- MDR[7:0]; 

ram=br ram=i mdr=bw mdr=high i=pl; 

// RAM[i++] 

<- MDR[15:0]; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

// fetch 

jump: 

i=br pc=bw; 

// I <- PC 


pc=br pc=low ram=bw ram=i i=pl; 

// PC[7:0] 

< — RAM[i++] 

pc=br pc=high ram=bw ram=i i=ml; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

// PC [15: 7] 

ctrl=load; 

■-I 

1 

1 

■H 

1 

1 

V 

jump8c: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR [7:0] 

<— RAM [pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15:7] 

<— RAM [pc++] 

pc=br sel=if_carry_8; 

// PC = (carry8?MDR:PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

// fetch 

jump8nc: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR [7:0] 

<— RAM [pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15:7] 

<— RAM [pc++] 

pc=br sel=if_not_carry_8; 

// PC = (not 

carry 8 ?MDR: PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

// fetch 

jump8z: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR [7:0] 

<— RAM [pc++] 



Version "C": 16-bit little-endian 


751 


mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] < — RAM[pc++] 

pc=br sel=if_zero_8; 

// PC = (zero8?MDR:PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

jump8nz: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] <— RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] < — RAM[pc++] 

pc=br sel=if_not_zero_8; 

// PC = (not_zero8?MDR:PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

jump8o: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] <— RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] <— RAM[pc++] 

pc=br sel=if_overflow_8; 

// PC = (overflow8?MDR:PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

jump8no: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] <— RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR [15:7] <— RAM[pc++] 

pc=br sel=if_not_overflow_8; 

// PC = (not_overflow8 ?MDR:PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

jump8n: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] <— RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] <— RAM[pc++] 

pc=br sel=if_negative_8; 

// PC = (negative8 ?MDR:PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

jump8nn: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] <— RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] < — RAM[pc++] 

pc=br sel=if_not_negative_8; 

// PC = (not_negative8 ?MDR: PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

jumpl6c: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] < — RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] < — RAM[pc++] 

pc=br sel=if_carry_l6; 

// PC = (carryl 6?MDR: PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

jumpl6nc: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] < — RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] < — RAM[pc++] 

pc=br sel=if_not_carry_l6; 

// PC = (not_carryl6?MDR:PC) 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; // fetch 

j ump16 z: 

mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] < — RAM[pc++] 

mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15: 7] < — RAM[pc++] 

pc=br sel=if_zero_l6; 

// PC = (zerol6?MDR:PC) 



752 


Version "C": 16-bit little-endian 


ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
jumpl 6 nz: 

mdr=br mdr=low ram=bw ram=p pc=pl; 
mdr=br mdr=high ram=bw ram=p pc=pl; 
pc=br sel=if_not_zero_l 6 ; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
jumpl 60 : 

mdr=br mdr=low ram=bw ram=p pc=pl; 
mdr=br mdr=high ram=bw ram=p pc=pl; 
pc=br sel=if_overflow_l 6 ; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
jumpl 6 no: 

mdr=br mdr=low ram=bw ram=p pc=pl; 
mdr=br mdr=high ram=bw ram=p pc=pl; 
pc=br sel=if_not_overflow_l 6 ; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
jumpl 6 n: 

mdr=br mdr=low ram=bw ram=p pc=pl; 
mdr=br mdr=high ram=bw ram=p pc=pl; 
pc=br sel=if_negative_l 6 ; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
jumpl 6 nn: 

mdr=br mdr=low ram=bw ram=p pc=pl; 
mdr=br mdr=high ram=bw ram=p pc=pl; 
pc=br sel=if_not_negative_l 6 ; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
call: 


i=br i=low ram=bw ram=p pc=pl sp=ml; 
i=br i=high ram=bw ram=p pc=pl sp=ml; 
ram=br ram=s pc=bw pc=low sp=pl; 
ram=br ram=s pc=bw pc=high sp=ml; 
pc=br i=bw; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
call_i: 


sp=m2; 

ram=br ram=s pc=bw pc=low sp=pl; 
ram=br ram=s pc=bw pc=high sp=ml; 
pc=br i=bw; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 


call_j: 

sp=m2; 

ram=br ram=s pc=bw pc=low sp=pl; 


ctrl=load; // fetch 

// MDR[7:0] <— RAM[pc++] 

// MDR [15:7] <— RAM[pc++] 

// PC = (not_zero 16?MDR: PC) 

ctrl=load; // fetch 

// MDR[7:0] <— RAM[pc++] 

// MDR [15:7] <— RAM[pc++] 

// PC = (overfl owl 6 ?MDR: PC) 

ctrl=load; // fetch 

// MDR[7:0] <— RAM[pc++] 

// MDR [15:7] <— RAM[pc++] 

// PC = (not_overflowl 6?MDR:PC) 

ctrl=load; // fetch 

// MDR[7:0] <— RAM[pc++] 

// MDR [15:7] <— RAM[pc++] 

// PC = (negatlvel6?MDR: PC) 

ctrl=load; // fetch 

// MDR[7:0] <— RAM[pc++] 

// MDR [15:7] <— RAM[pc++] 

// PC = (not_negatlvel6?MDR:PC) 

ctrl=load; // fetch 

// I[7:0] <— RAM[pc++], SP — 
// I [15: 7] <— RAM[pc++], SP — 
// RAM [ sp+-h] <- PC[7:0], SP++ 
// RAM[sp—] <- PC [15: 8], SP — 
// PC <- I; 
ctrl=load; // fetch 

// SP <— (SP - 2) 

// RAM[sp++] <- PC[7:0], SP++ 
// RAM[sp—] <- PC [15: 8], SP — 
// PC <- J; 

ctrl=load; // fetch 

// SP <— (SP - 2) 

// RAM[sp++] <- PC[7:0], SP++ 



Version "C": 16-bit little-endian 


753 


ram=br ram=s 

pc=bw pc=high sp=ml ; 


// RAM [sp — 

] <- PC[15:8], SP — 

pc=br j=bw; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

o 

ii 

i— i 

// PC <- J; 

ctrl=load; 

// fetch 

return : 

pc=br pc=low 

ram=bw ram=s sp=pl; 


// PC[7:0] 

<- RAM[sp++] ; 

pc=br pc=high ram=bw ram=s sp=pl; 


// PC[15:8] 

<- RAM [sp++] ; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; 

// fetch 

push8_i: 

sp=ml; 

ram=br ram=s 

i=bw i=low; 


// SP—; 

// RAM[sp] 

<- I[7:0]; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; 

// fetch 

push8_j : 

sp=ml ; 

ram=br ram=s 

j=bw j=low; 


// SP—; 

// RAM[sp ] 

<- J[7 : 0] ; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

O 

II 

ctrl=load; 

// fetch 

push8_a : 

sp=ml ; 

ram=br ram=s 

a=bw a=low; 


// SP—; 

// RAM[sp] 

<- A[7 : 0] ; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

O 

II 

ctrl=load; 

// fetch 

push8_b : 

sp=ml ; 

ram=br ram=s 

b=bw b=low; 


// SP—; 

// RAM[sp] 

<- B [7 : 0] ; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; 

// fetch 

push8_bp: 

sp=ml; 

ram=br ram=s 

bp=bw bp=low; 


// SP—; 

// RAM[sp] 

<- BP[7:0]; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; 

// fetch 

push8_mdr: 

sp=ml; 

ram=br ram=s 

mdr=bw mdr=low; 


// SP—; 

// RAM[sp] 

<- MDR[7:0]; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

O 

II 

ctrl=load; 

// fetch 

push8_f 1 : 

sp=ml; 

ram=br ram=s 

fl=bw fl=low; 


// SP—; 

// RAM[sp ] 

<- FL[7:0]; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; 

// fetch 

pop8_i : 

i=br i=low 

ram=bw ram=s sp=pl 


// I[7:0] < 

'— RAM[sp++] ; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; 

// fetch 

pop8_j : 

j =br j=low 

ram=bw ram=s sp=pl; 


// J[7 : 0] < 

'— RAM[sp++] ; 

ir=aux ir=br 

ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; 

// fetch 

pop8_a : 



754 


Version "C": 16-bit little-endian 


a=br a=low ram=bw ram=s sp=pl; 


// A[7:0] <— RAM[sp++]; 

ir=aux ir=br ram=aux ram=bw ram=p 

o 

ii 

ctrl=load; // fetch 

pop8_b: 

b=br b=low ram=bw ram=s sp=pl; 


// B[7:0] <— RAM[sp++]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

pop8_bp: 

bp=br bp=low ram=bw ram=s sp=pl; 


// BP[7:0] <— RAM[sp++]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

pop8_mdr: 

mdr=br mdr=low ram=bw ram=s sp=pl 

- r 

// MDR[7:0] <— RAM[sp++]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

pop8_f1: 

fl=br fl=low ram=bw ram=s sp=pl; 


// FL[7:0] < — RAM[sp++]; 

ir=aux ir=br ram=aux ram=bw ram=p 

O 

II 

1— i 

ctrl=load; // fetch 

pushl6_i: 

sp=m2; 


// SP <— (SP ~ 2) 

ram=br ram=s i=bw i=low sp=pl; 


// RAM[sp++] <- I[7:0]; 

ram=br ram=s i=bw i=high sp=ml; 


// RAM[sp—] <- I[15:8]; 

ir=aux ir=br ram=aux ram=bw ram=p 

o 

II 

1— i 

ctrl=load; // fetch 

pushl6_j: 

sp=m2; 


// SP <— (SP ~ 2) 

ram=br ram=s j=bw j=low sp=pl; 


// RAM[sp++] <- J[7:0]; 

ram=br ram=s j=bw j=high sp=ml; 


// RAM[sp—] <- J[15:8] ; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

pushl6_a: 

sp=m2; 


// SP <— (SP ~ 2) 

ram=br ram=s a=bw a=low sp=pl; 


// RAM[sp++] <- A[7:0]; 

ram=br ram=s a=bw a=high sp=ml; 


// RAM[sp—] <- A[15:8] ; 

ir=aux ir=br ram=aux ram=bw ram=p 

o 

II 

1— i 

ctrl=load; // fetch 

pushl6_b: 

sp=m2; 


// SP <— (SP ~ 2) 

ram=br ram=s b=bw b=low sp=pl; 


// RAM[sp++] <- B[7:0]; 

ram=br ram=s b=bw b=high sp=ml; 


// RAM[sp—] <- B[15:8]; 

ir=aux ir=br ram=aux ram=bw ram=p 

O 

II 

1— i 

ctrl=load; // fetch 

pushl6_bp: 

sp=m2; 


// SP <— (SP ~ 2) 

ram=br ram=s bp=bw bp=low sp=pl; 


// RAM[sp++] <- BP[7:0]; 

ram=br ram=s bp=bw bp=high sp=ml; 


// RAM[sp—] <- BP[15:8]; 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl 

ctrl=load; // fetch 

pushl6_mdr: 

sp=m2; 


// SP <— (SP ~ 2) 

ram=br ram=s mdr=bw mdr=low sp=pl 

- r 

// RAM[sp++] <- MDR[7:0]; 



Version "C": 16-bit little-endian 


755 


ram=br ram=s mdr=bw mdr=high sp=ml; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
pushl6_f1: 
sp=m2; 

ram=br ram=s fl=bw fl=low sp=pl; 
ram=br ram=s fl=bw fl=high sp=ml; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
popl6_i: 

i=br i=low ram=bw ram=s sp=pl; 
i=br i=high ram=bw ram=s sp=pl; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
popl6_j: 

j=br j=low ram=bw ram=s sp=pl; 
j=br j=high ram=bw ram=s sp=pl; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
popl6_a: 

a=br a=low ram=bw ram=s sp=pl; 
a=br a=high ram=bw ram=s sp=pl; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
popl6_b: 

b=br b=low ram=bw ram=s sp=pl; 
b=br b=high ram=bw ram=s sp=pl; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
popl6_bp: 

bp=br bp=low ram=bw ram=s sp=pl; 
bp=br bp=high ram=bw ram=s sp=pl; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
popl6_mdr: 

mdr=br mdr=low ram=bw ram=s sp=pl; 
mdr=br mdr=high ram=bw ram=s sp=pl; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
popl6_f1: 

fl=br fl=low ram=bw ram=s sp=pl; 
fl=br fl=high ram=bw ram=s sp=pl; 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl 
c8tol6u: 


// RAM[sp—] <- MDR [15:8]; 

ctrl=load; // fetch 

// SP <— (SP - 2) 

// RAM[sp++] <- FL [7:0]; 

// RAM[sp—] <- FL [15:8]; 

ctrl=load; // fetch 

// I[7:0] < — RAM[sp++]; 

// I [15:0] <— RAM[sp++]; 

ctrl=load; // fetch 

// J[7: 0] < — RAM[sp++]; 

// J[15: 0] <— RAM[sp++]; 

ctrl=load; // fetch 

// A[7:0] <— RAM[sp++]; 

// A[15:0] <— RAM[sp++]; 

ctrl=load; // fetch 

// B[7: 0] <— RAM[sp++]; 

// B [15: 0] <— RAM[sp++]; 

ctrl=load; // fetch 

// BP [7:0] <— RAM[sp++]; 

// BP [15:0] <— RAM[sp++]; 

ctrl=load; // fetch 

// MDR[7:0] <— RAM[sp++] ; 
// MDR [15:0] <— RAM[sp++] ; 

ctrl=load; // fetch 

// FL[7:0] <— RAM[sp++]; 

// FL[15:0] <— RAM[sp++]; 

ctrl=load; // fetch 


a=br alu=bw alu=a alu=rank8 fl=br fl=aux // A[15:0] <- A[7:0 ], 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; // fetch; 


c8tol6s: 


a=br alu=bw alu=a alu=rank8 alu=sign fl=br fl=aux // A[15:0] <— A[7:0] r 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; // fetch; 

equal: 



756 Version 


a=br alu=bw alu=a alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

not: 

a=br alu=bw alu=not alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

and: 

a=br alu=bw alu=and alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

nand: 

a=br alu=bw alu=nand alu=rankl6 fl=br fl=aux // A < 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

or: 

a=br alu=bw alu=or alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

nor: 

a=br alu=bw alu=nor alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

xor: 

a=br alu=bw alu=xor alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

nxor: 

a=br alu=bw alu=nxor alu=rankl6 fl=br fl=aux // A < 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

add: 

a=br alu=bw alu=add alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

sub: 

a=br alu=bw alu=sub alu=rankl6 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

addc8: 

a=br alu=bw alu=addc alu=rank8 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

subb8: 

a=br alu=bw alu=subb alu=rank8 fl=br fl=aux // A < 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

addcl6: 

a=br alu=bw alu=addc alu=rankl6 f l=br fl=aux // A < 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

subbl6: 

a=br alu=bw alu=subb alu=rankl6 f l=br fl=aux // A < 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

lshl8: 


C": 16-bit little-endian 


- A, fetch 


- NOT A, fetch 


- A AND B, fetch 


- A NAND B, fetch 


- A OR B, fetch 


- A NOR B, fetch 


- A XOR B, fetch 


- A NXOR B, fetch 


- A+B, fetch 


- A-B, fetch 


- A+B+carry, fetch 


- A-B-borrow, fetch 


- A+B+carry, fetch 


- A-B-borrow, fetch 



Version "C": 16-bit little-endian 


757 


a=br alu=bw alu=lshl alu=rank8 fl=br fl=aux // A <— 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

lshr8: 

a=br alu=bw alu=lshr alu=rank8 fl=br fl=aux // A <- 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

ashl8: 

a=br alu=bw alu=ashl alu=rank8 alu=sign fl=br fl=aux 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

ashr8: 

a=br alu=bw alu=ashr alu=rank8 alu=sign fl=br fl=aux 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
rotcl8: 

a=br alu=bw alu=rotcl alu=rank8 fl=br fl=aux // A <- 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
rotcr8: 

a=br alu=bw alu=rotcr alu=rank8 fl=br fl=aux // A <- 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

rotl8: 

a=br alu=bw alu=rotl alu=rank8 fl=br fl=aux // A <- 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

rotr8: 

a=br alu=bw alu=rotr alu=rank8 fl=br fl=aux // A <— 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
lshll6: 

a=br alu=bw alu=lshl alu=rankl6 fl=br fl=aux // A <— 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
lshrl6: 

a=br alu=bw alu=lshr alu=rankl6 fl=br fl=aux // A <— 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
ashll6: 

a=br alu=bw alu=ashl alu=rankl6 alu=sign fl=br fl=aux 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
ashrl6: 

a=br alu=bw alu=ashr alu=rankl6 alu=sign fl=br fl=aux 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
rotcll6: 

a=br alu=bw alu=rotcl alu=rankl6 fl=br fl=aux // A <— 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
rotcrl6: 

a=br alu=bw alu=rotcr alu=rankl6 fl=br fl=aux // A <— 
ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 
rotll6: 


A «, fetch 


A », fetch 


// A <- A*2, 

// fetch: 

// A <- A/2, fetch 


rot cl (A), fetch 


rotcr(A) r fetch 


rotl (A) , fetch 


rotr (A), fetch 


A «, fetch 


A », fetch 


// A <- A*2, 
// fetch; 

// A <- A/2, 
// fetch; 


rot cl(A) , fetch 


rotcr(A) , fetch 



758 


Version "C": 16-bit little-endian 



a=br alu=bw alu=rotl alu=rank!6 fl=br fl=aux // A <- rotl(A), fetch 


ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl ctrl=load; 

rotrl6: 



a=br alu=bw alu=rotr alu=rank!6 fl=br fl=aux // A <- rotr(A), fetch 

in: 

ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl ctrl=load; 


ioa=br ram=bw ram=p pc=pl; 

// IOA <- RAM [pc++] ; 


ioc=req; 

// I/O request; 


ctrl=nop; 

// does not do anything 


a=br ioc=bw 

// A <- I/O, fetch; 


ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl ctrl=load; 

out 




ioa=br ram=bw ram=p pc=pl; 

// IOA <- RAM[pc++]; 


ioc=br a=bw; 

// I/O <- A 


ioc=req 

// I/O request, fetch; 


ir=aux ir=br ram=aux ram=bw ram=p 

pc=pl ctrl=load; 

ifack_jump: 



ioa=br ram=bw ram=p pc=pl; 

// IOA <- RAM[pc++]; 


mdr=br mdr=low ram=bw ram=p pc=pl; 

// MDR[7:0] <- RAM[pc++]; 


mdr=br mdr=high ram=bw ram=p pc=pl; 

// MDR[15:8] <- RAM[pc++]; 


a=br ioc=bw ioc=isack; 

// A <- I/O is ack; 


a=br alu=a alu=rank8 alu=sign fl=br 

fl=aux; // A[15:0] <— A[7:0]; 


pc=br sel=if_not_zero_8; 

// PC = (not_zero8?MDR:PC); 


ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; // fetch 

int 

// push FL 



sp=m2; 

// SP <— (SP ~ 2) 


ram=br ram=s fl=bw fl=low sp=pl; 

// RAM[sp++] <- FL[7:0]; 


ram=br ram=s fl=bw fl=high sp=ml; 

// RAM[sp — ] <- FL [15:8]; 


// reset interrupt enable flag, PC++ 


// (PC is incremented to jump the argument, before it is saved 
// inside the stack ). 

fl=br fl=aux alu=cleari pc=pl; 

// push PC 


sp=m2; 

// SP <— (SP ~ 2) 


ram=br ram=s pc=bw pc=low sp=pl; 

// RAM[sp++] <- PC[7:0]; 


ram=br ram=s pc=bw pc=high sp=ml; 

// push I 

// RAM[sp—] <- PC [15:8]; 


sp=m2; 

// SP <— (SP ~ 2) 


ram=br ram=s i=bw i=low sp=pl; 

// RAM[sp++] <- I[7:0]; 


ram=br ram=s i=bw i=high sp=ml; 

// RAM[sp—] <- I[15:8]; 


// Set the PC register back so that 

the argument 



Version "C": 16-bit little-endian 


759 


// can be read . 

pc=ml; 

// 

i=br ivt=bw ivt=intb ram=bw ram=aux ram : 

=p pc=pl; // X <- IVT <- RAM[pc++]; 

pc=br pc=low ram=bw ram=i i=pl; 

// PC[7:0] <— RAM[i++] 

pc=br pc=high ram=bw ram=i i=ml; 

// PC [15:7] < — RAM[i — ] 

// pop I 

i=br i=low ram=bw ram=s sp=pl; 

// I[7:0] <— RAM[sp++]; 

i=br i=high ram=bw ram=s sp=pl; 

// I[15:0] <— RAM[sp++]; 

// fetch 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

iret: 

// pop PC 

pc=br pc=low ram=bw ram=s sp=pl; 

// PC[7:0] <- RAM[sp++]; 

pc=br pc=high ram=bw ram=s sp=pl; 

// PC [15:8] <- RAM[sp++]; 

// pop FL 

fl=br fl=low ram=bw ram=s sp=pl; 

// FL[7:0] <— RAM[sp++]; 

fl=br fl=high ram=bw ram=s sp=pl; 

// FL[15:0] <— RAM[sp++]; 

// fetch 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl 

ctrl=load; 

irq: 

// push FL 

sp=m2; 

// SP <— (SP ~ 2) 

ram=br ram=s f l=bw fl=low sp=pl; 

// RAM[sp++] <- FL[7:0] ; 

ram=br ram=s f l=bw fl=high sp=ml; 

// RAM[sp—] <- FL [15:8] ; 

// reset interrupt enable flag 

f l=br fl=aux alu=cleari; 

// Restore the PC correct value: PC is 

currently located after the 

// opcode of an instruction that is not 

currently executed, 

// because there is a hardware interrupt to serve; that is why the 

// correct value to save inside the stack is PC-1 . 

pc=ml; 

// PC—; 

// push PC 

sp=m2; 

// SP <— (SP - 2) 

ram=br ram=s pc=bw pc=low sp=pl; 

// RAM[sp++] <- PC[7:0]; 

ram=br ram=s pc=bw pc=high sp=ml; 

// RAM[sp—] <- PC[15:8]; 

// push I 

sp=m2; 

// SP <— (SP ~ 2) 

ram=br ram=s i=bw i=low sp=pl; 

// RAM[sp++] <- I[7:0]; 

ram=br ram=s i=bw i=high sp=ml; 

// RAM[sp—] <- I[15:8]; 

// 

i=br ivt=bw ivt=inta; 

// I <- IVT <- IRQ; 



760 


Version "C": 16-bit little-endian 


pc=br pc=low ram=bw ram=i i=pl; 
pc=br pc=high ram=bw ram=i i=ml; 

// pop I 

i=br i=low ram=bw ram=s sp=pl; 
i=br i=high ram=bw ram=s sp=pl; 

// 

irq=done; 

// fetch 

ir=aux ir=br ram=aux ram=bw ram= 
ivtl: 

i=br i=low ram=bw ram=p pc=pl; 
i=br i=high ram=bw ram=p pc=pl; 
ivt=br i=bw; 

ir=aux ir=br ram=aux ram=bw ram= 
imrl: 


// PC[7:0] <— RAM[1++] 

// PC [15: 7] <— RAM[i—] 

// I[7:0] <— RAM[sp++]; 
// I[15:0] <— RAM[sp++]; 


: p pc=pl ctrl=load; 

// I[7:0] <- RAM[pc++]; 
// I[15:8] <- RAM[pc++]; 
// IVT <- MDR; 

: p pc=pl ctrl=load; // fetch 


irq=br ram=bw ram=p pc=pl; // IRQ <- RAM[pc++]; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; // fetch 
cleari: 

fl=br fl=aux alu=cleari irq=done 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 


seti : 

fl=br fl=aux alu=seti irq=done 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

clearc: 

fl=br fl=aux alu=clearc 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

setc: 

fl=br fl=aux alu=setc 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 


cmp: 

fl=br fl=aux alu=sub // FL (A - B) ; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

test: 

fl=br fl=aux alu=and // FL (A AND B) ; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

inc_i: 

i=pl // I++, fetch; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

inc_j: 

j=pl // J++, fetch; 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 


inc_a: 



Version "C": 16-bit little-endian 


761 



a=pl 





// A++, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

inc_ 

_b: 







b=pl 





// B++, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

inc_ 

_bp: 







bp=pl 





// BP++, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

inc_ 

_sp: 







sp=pl 





// SP++, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

inc_ 

_mdr: 







mdr=pl 





// MDR++, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

inc_ 

i— i 

4-1 

1 







fl=pl 





// FL++, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

dec_ 

_i : 







\ —i 
£ 

II 

-H 





// I —, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

dec_ 








j=ml 





// J —, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

dec_ 

_a: 







a=ml 





// A —, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

dec_ 

_b: 







b=ml 





// B —, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

o 

CD 

T3 

_bp: 







bp=ml 





// BP — , fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

dec_ 

_sp: 







sp=ml 





// SP — , fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

dec_ 

_mdr: 







mdr=ml 





// MDR — , fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

dec_ 

i—i 

4-1 

1 







fl=ml 





// FL —, fetch; 


ir=aux 

ir=br 

ram=aux 

ram=bw 

ram=p 

pc=pl ctrl=load; 

// 









762 


Version "C": 16-bit little-endian 


stop: 

ctrl=stop; // stop clock 

// if resumed, fetch: 

ir=aux ir=br ram=aux ram=bw ram=p pc=pl ctrl=load; 

// 

end 


11.11 Interrupts management 

There are three types of interrupts: those generated internally by the 
CPU, those generated by the hardware (IRQ) and the software in¬ 
terrupts. The CPU internal interrupts can range from INTO to INT3, 
but currently there is only INTO which is related to the identification 
of a wrong opcode. The hardware interrupts can range from INT4 
to INT7 and match respectively the range IRQO to IRQ3. Software 
interrupts can range from INT8 to INT15. The IVT table (interrupt 
vector table) must be prepared through the macrocode, which must 
initialize the IVT register with the address of the table location, as 
in the following example: 


begin macrocode 

@ 0 





jump #start 





nop 






interrupt_vector 

_table: 





.short 

0x0025 

// 

CPU 

# 

op code_ error 

.short 

0x0024 

// 

CPU 

# 

default_interrupt_routine 

.short 

0x0024 

// 

CPU 

# 

default_±nterrupt_rout±ne 

.short 

0x0024 

// 

CPU 

# 

default_±nterrupt_rout±ne 

.short 

0x0024 

// 

IRQ 

# 

default_±nterrupt_rout±ne 

.short 

0x0024 

// 

IRQ 

# 

default_interrupt_routine 

.short 

0x0024 

// 

IRQ 

# 

default_interrupt_routine 

.short 

0x0024 

// 

IRQ 

# 

default_lnterrupt_rout±ne 

.short 

0x0024 

// 

software 

# 

default_±nterrupt_rout±ne 

.short 

0x0024 

// 

software 

# 

default_±nterrupt_rout±ne 




Version "C": 16-bit little-endian 


763 


.short 

0x0024 

// 

software 

# 

.short 

0x0024 

// 

software 

# 

.short 

0x0024 

// 

software 

# 

.short 

0x0024 

// 

software 

# 

.short 

0x0024 

// 

software 

# 

.short 

0x0024 

// 

software 

# 


default_interrupt_routine: 
iret 

op_code_error: 

stop 


default_interrupt_routine 

default_interrupt_routine 

default_interrupt_routine 

default_interrupt_routine 

default_interrupt_routine 

default_interrupt_routine 


start: 


loadl6 #sp_base 
mv %MDR, %SP 

ivtl #interrupt_vector_table 
imrl OxOF // tutti 
set i 


sp_base: 

.short 0x0080 

end 


The table might also be shorter, if there is no need for the software 
interrupts. 

The occurrence of an interrupt (CPU, hardware or software) involves 
the following: the FL register is saved on top of the stack, the inter¬ 
rupt enable flag is disabled, the PC register is saved on top of the 
stack. The iret instruction restores the PC and then the FL reg¬ 
isters. But while the conclusion of an interrupt takes place always 
in the same way, through the description of the opcode iret, the 
start is different in the three cases. If it comes to interruption due to 
a wrong opcode, the microcode routine at the label op_error is per- 



764 


Version "C": 16-bit little-endian 


formed; if it is a hardware interrupt, the microcode routine starting at 
the irq label is run, as specified by the dip-switch inside the control 
unit; if it is a software interrupt, the microcode routine starting at the 
int label is executed. The three situations are different: 

• The interrupt due to an incorrect opcode depends on an error from 
the code read inside the RAM memory, but it is not known the 
extent of this damage. Not being able to guess, the best choice 
for the routine associated to the interruption should coincide with 
the CPU halt, otherwise, it might be the case to try to ignore the 
wrong opcode and just try the next memory cell, without being 
able to know if there is possibly an argument to the wrong opcode 
just read. 

• The hardware interrupt (IRQ) occurs asynchronously with re¬ 
spect to the CPU activity and it is served only when the CPU 
itself would be ready to execute a new opcode. In this condi¬ 
tion, the PC register already points to the memory location next 
to the opcode that would have to be executed, so, before saving 
the PC register inside the stack, it is necessary to move back the 
PC one position: this way it points to the position of the opcode 
that must be executed after the interrupt is served. The microcode 
related to a hardware interrupt has also the task, once read the ad¬ 
dress matching the interrupt from the IVT table, to cancel the 
pending request from the IRQ module. This is done by sending 
a signal through the control bus, which in the IRQ module is im¬ 
plemented as irq_done. It is then a task of the logic inside the 
IRQ module to know what is actually the IRQ signal to reset. At 
the same time, the IRQ module might require the management 
of another interrupt, but this management would be temporarily 



Version "C": 16-bit little-endian 


765 


suspended, because the interrupt enable flag is disabled (it is dis¬ 
abled immediately after the FL register is saved on the stack). 

• The software interrupt is easier to manage, because it happens 
in a predictable way, without really interrupting the control unit 
activity. 

When an interruption occurs also exists the need to jump properly to 
the routine provided in the IVT table. The IVT register has two sep¬ 
arate inputs to receive the interrupt number to convert to memory ad¬ 
dress: one is connected to the auxiliary bus, which is also connected 
to the BUS module and the RAM module; the other is connected 
to the IRQ module. When a CPU internal interrupt is generated, the 
IVT module is controlled directly by the control unit, through the 
BUS module; when a hardware interrupt is received, the IVT mod¬ 
ule is driven by the IRQ module; when it is a software interrupt, the 
IVT module receives the interrupt number from the RAM, supplied 
as an argument to the opcode. It should also be noticed that with the 
software interrupt, any interrupt number can be specified. 

11.12 Module "RTC": real time clock 

The RTC module (real time clock) produces one pulse per second 
through the hardware interrupt IRQO. If the IRQO is enabled inside 
the IRQ module, an INT4 is requested at every second. INT4 is 
translated into the fifth position inside the IVT table. The RTC mod¬ 
ule is described only by Verilog code: 


766 


Version "C": 16-bit little-endian 


Listing 11.42. Module RTC. 


module RTC (T); 


output T; 


reg p; 


always 


begin 


p = 0; 


$tkg$wait 

(500) ; 

p = 1; 


$tkg$wait 

(500); 

end 


assign T = p; 


endmodule 



11.13 Module "TTY" 

The module TTY, for the video-keyboard terminal management, is 
almost the same as the previous version of the project: it adds an out¬ 
put connected to the keyboard confirmation signal (acknowledge), to 
control the IRQ1 interrupt. In this way, when the user press a key on 
the keyboard, an IRQ1 interrupt is produced: the routine associated 
to the hardware interrupt can be used to execute the code necessary 
to handle what was typed. 



Version "C": 16-bit little-endian 


767 


Figure 11.43. Module TTY . 



Listing 11.44. Verilog code describing the module terminal. 


module terminal(K_DATA, 

K_REQ, K_ACK, 

S_DATA, 

S_REQ, S_ACK, CLR) ; 

output K_ACK; 


output S_ACK; 


output [7:0] K_DATA; 


input [7:0] S_DATA; 


input K_REQ; 


input S_REQ; 
































































































































j 


Version "C": 16-bit little-endian 


input CLR; 
reg k_ready; 
reg [7:0] key; 
reg s_ready; 

initial 
begin 

k_ready = 0; 
s_ready = 0; 
key = 0; 
end 

always 
begin 

@(posedge CLR) 
k_ready = 0; 
s_ready = 0; 
key = 0; 
end 

initial $tkg$post("TERMINAL”,"%m"); 

always 

begin 

@ (posedge K_REQ); 

# 5; 

key = $tkg$recv("%m.KD"); 

# 5; 



Version "C": 16-bit little-endian 


/Ob 


k_ready = l'bl; 

# 5; 

@ (negedge K_REQ) ; 

# 5; 

k_ready = 1'bO; 
end 

always 

begin 

@(posedge S_REQ) ; 

# 5; 

$tkg$send("%m. SD",S_DATA) ; 

# 5; 

s_ready = l'bl; 

# 5; 

@(negedge S_REQ); 

# 5; 

s_ready = 1'bO; 
end 

assign S_ACK = s_ready; 
assign K_DATA = key; 
assign K_ACK = k_ready; 


endmodule 




770 


Version "C": 16-bit little-endian 


Listing 11.45. File ‘share/tkgate/vpd/terminal.tel’ for 

TCL interface. _ 

image create bitmap txtcurs -file "$bd/txtcurs.b" 

VPD::register TERMINAL 
VPD::allow TERMINAL::post 
VPD::allow TERMINAL::data 

namespace eval TERMINAL { 

# Public variables declarations: the variables $terminal_... 

# are arrays of which only the element $n is used; 

# that element identifies uniquely the working interface instance. 

variable terminal_w 
variable terminal_pos 

# 

variable KD 

# Function requested by TKGate to create the interface. 

proc post {n} { 

variable terminal_w 
variable terminal_pos 

# Create the window and save the object element in a $terminal_w array element. 

set terminal_w($n) [VPD::createWindow "TERMINAL $n" -shutdowncommand "TERMINAL::unpost $n"] 

# For convenience, copy the object reference inside the local 

# variable $w; then, the variable $w will be used as a reference to the object. 

set w $terminal_w($n) 
text $w.txt -state disabled 
pack $w.txt 

# Put the cursor at the end of the displayed text. 

$w.txt image create end -image txtcurs 

# Bind the keyboard input, related to the object represented by 

# $terminal_w ($n), to the function sendChar. 

bind $w <KeyPress> "TERMINAL::sendChar $n \"%A\"" 

# Open a reading channel, named «SD» (screen data), 

# and associate it to the function «data»; moreover, open a 

# writing channel, named «KD» (keyboard data). 

if {[info exists ::tkgate_islnitialized]} { 

VPD::outsignal $n.KD TERMINAL::KD($n) 

VPD::insignal $n.SD -command "TERMINAL::data $n" -format %d 

} 

# Reset the character count, used to count the characters displayed 

# on screen. 

set terminal_pos($n) 0 

} 

# Function that receives the typing and put it into the 

# channel «KD», related to the current interface instance. 

proc sendChar {n key} { 
variable KD 

if { [string length $key ] == 1 } { 
binary scan $key c c 
set TERMINAL::KD($n) $c 

} 



Version "C": 16-bit little-endian 


111 


} 

# Function that TKGate requires to destroy the interface. 

proc unpost {n} { 

variable terminal_w 
variable terminal_pos 
destroy $terminal_w($n) 
destroy $terminal_pos($n) 
unset terminal_w($n) 
unset terminal_pos($n) 

} 

# Function used to get the data to display on screen. 

proc data {n c} { 

variable terminal_w 
variable terminal_pos 

# For convenience, copy the object reference representing the 

# interface, inside the variable $w. 

set w $terminal_w($n) 
catch { 

# The variable $c contains the character to display. 

if { $C == 7 } { 

# BEL 

bell 

return 

} elseif { $c == 127 | | $c == 8 } { 

# DEL I BS 

if { $terminal_pos($n) > 0 } { 

# Delete the last displayed character, but only if the 

# characters counter is greater than zero, otherwise 

# the cursor would disappear and the next characters 

# would be located in an invisible screen area. 

$w.txt configure -state normal 
$w.txt delete "end - 3 chars" 

$w.txt see end 

$w.txt configure -state disabled 

set terminal_pos($n) [expr {$terminal_pos($n) - l}] 

} 

return 

} elseif { $c == 13 } { 

# Convert CR to LF. 

set c 10 

} 

# Convert the character number into a visible symbol. 

set x [format %c $c] 

# Display the symbol. 

$w.txt configure -state normal 
$w.txt insert "end - 2 chars" $x 
$w.txt see end 

$w.txt configure -state disabled 

# Update the displayed characters counter. 

set terminal_pos($n) [expr {$terminal_pos($n) + l}] 

} 

} 



772 


Version "C": 16-bit little-endian 


} 


11.14 Module "HDD" 

The HDD module is new compared to the previous version: it is 
an interface that simulates a set of eight units of mass storage, each 
one divided into sectors of 512 bytes. The device is accessed with 
different I/O addresses depending on the type of operation that is to 
be made. 



Version "C": 16-bit little-endian 


773 


Figure 11.46. Module HDD. 



Listing 11.47. Verilog code describing the module hd. 


module 

hd(DRIVE, SECTOR, 

BYTE, 

WRITE, DATA_IN, 


DATA_OUT, REQ, 

ACK, 

CLR) ; 

input 

[2:0] DRIVE; 



input 

WRITE, REQ, CLR; 



input 

[15:0] SECTOR; 



input 

[9:0] BYTE; 



input 

[7:0] DATA_IN; 





















































































































774 


Version "C": 16-bit little-endian 


output [7:0] DATA_OUT; 
output ACK; 

// 

integer _data_out; 
integer _ack; 

// 

reg [7:0] buffer[0:1023]; 

reg [8*24-1:0] filename = n hd0_sector_000000000.mem 

// 

integer i; 
integer sector_8; 
integer sector_7; 
integer sector_6; 
integer sector_5; 
integer sector_4; 
integer sector_3; 
integer sector_2; 
integer sector_l; 
integer sector_0; 
integer x; 

// 

initial 

begin 

for (i=0; i<1024; i=i+l) 
begin 

// 

// Initial buffer reset with 00. 

// 

buffer [i] = 8'h00; 


If 



Version "C": 16-bit little-endian 


775 


end 

_ack = 0; 

_data_out = 0; 
x = 0; 
end 

// 

always 

begin 

@(posedge CLR) 

_ack = 0; 

_data_out = 0; 
x = 0; 
end 

// 

// 

// 

always 

begin 

// 

// Start after a positive edge from REQ!. 

// 

@(posedge REQ); 

# 10 ; 

// 

// Define the sector file name. 

// 

x = SECTOR; 
sector_0 = x%10; 
x = x /10; 



776 


Version "C": 16-bit little-endian 


sector_l = x%10; 
x = x/10; 
sector_2 = x%10; 
x = x /10; 
sector_3 = x%10; 
x = x /10; 
sector_4 = x%10; 
x = x/10; 
sector_5 = x%10; 
x = x/10; 
sector_6 = x%10; 
x = x/10; 
sector_7 = x%10; 
x = x /10; 
sector_8 = x%10; 
// 


// The string starts 

from right 

to left! 

// 




filename[12*8+7:12*8] 

= sector_ 

8 

• < 

00 

00 

+ 

filename[11*8+7:11*8] 

= sector_ 

7 

+ 8'd4 8; 

filename[10*8+7:10*8] 

= sector_ 

6 

• < 

00 

00 

+ 

filename[9*8+7:9*8] = 

sector_5 

+ 

• < 

00 

< 

00 

filename[8*8+7:8*8] = 

sector_4 

+ 

8'd4 8; 

filename[7*8+7:7*8] = 

sector_3 

+ 

• < 

00 

< 

00 

filename[6*8+7:6*8] = 

sector_2 

+ 

8'd4 8; 

filename[5*8+7:5*8] = 

sector_l 

+ 

8'd4 8; 

filename[4*8+7:4*8] = 

sector_0 

+ 

8'd4 8; 

// 




filename[21*8+7:21*8] 

= DRIVE + 


• < 

00 

< 

00 



Version "C": 16-bit little-endian 


777 


// 

if (WRITE) 
begin 

// 

// Put data inside the buffer. 

// 

buffer [BYTE] = DATA_IN; 

// 

// Save the buffer to disk. 

// Please remember that $writememh() 
// must be enabled inside TKGate 
// configuretion! 

// 

$writememh(filename, buffer); 

// 

// Return the same data read. 

// 

_data_out = buffer[BYTE]; 
end 
else 
begin 

// 

// Get data from disk to the buffer. 

// 

$readmemh(filename, buffer); 

// 

// Return the data required. 

// 

_data_out = buffer[BYTE]; 



778 


Version "C": 16-bit little-endian 


end 

// 

// Acknowledge. 

// 

_ack = 1; 

// 

// PiTait the end of request 
// (the negative edge) 

// before restarting the loop. 
// 

@(negedge REQ); 

# 10 ; 

// 

// Now become ready again. 

// 

_ack = 0; 
end 

// 

assign DATA_0UT = _data_out; 
assign ACK = _ack; 

// 

endmodule 


Since this is a new module, it is important to describe the behaviour 
of the hd module, which has just been shown as a Verilog source: the 
inputs DRIVE , SECTOR and BYTE are used to uniquely identify 
a byte, belonging to a certain sector of a certain storage device. In 
practice, each virtual storage unit is divided into sectors, from the 
first, equal to zero, to the last, equal to 65536. Since the sector size 



Version "C": 16-bit little-endian 779 

is 512 bytes, these storage units have virtually a maximum capacity 
of 32 Mbyte. 

The input WRITE allows to select a write access to the device stor¬ 
age, otherwise a read access is intended. The access to the unit is 
one byte at a time and the output DATAjOUT should be used for 
reading, while the input DATA_IN should be used for writing. The 
inputs and outputs REQ , ACK and CLR operate in a predictable 
manner, in accordance with what is already described for the termi¬ 
nal device (keyboard and screen). 

To use the HDD device, it is necessary to provide the coordinates of 
the byte to which the access should be done, writing to the I/O ports 
4, 5 and 6, respectively for the storage unit, the field and the byte. 
Then it is possible to ask a read access (I/O address 2) or write access 
(I/O address 3). When a read or write operation has been completed, 
the confirmation signal (acknowledge) is issued from the HDD mod¬ 
ule and sent to the IRQ module, as an IRQ2 signal. Anyway, it is not 
necessary to enable IRQ2 to access the HDD module, because read¬ 
ing is always possible, with the difference that if the read data is not 
yet valid, the value is negative. Similarly, after writing, it is possible 
to verify the write completion through a read of the same byte: if 
the value obtained is negative, it means that the operation is not yet 
complete. 

The module hd allows to use the virtual storage devices without the 
need to first create files: when accessing for the first time, in writing, 
to an area that had never been used before, the file that represents 
the sector is created on the fly (the file is created inside the directory 
where TKGate is working). If it is read a sector that does not exist 
already, it is produced just a null value (00i 6 ) without creating the 



780 


Version "C": 16-bit little-endian 


associated file. The files that are created on writing match the pattern 
i hdn_sector_sssssssss .mem’. 

11.15 Macrocode: terminal usage example, 
through interrupts 

The following code performs the reading of the keyboard, through 
the interruption generated by the keyboard itself, and the represen¬ 
tation of the text typed on the screen. The begin of code defines the 
location of the IVT table and the associated code for the various table 
elements. 

Listing 11.48. Macrocode managing a terminal through the key¬ 
board interrupts. 

begin macrocode @ 0 
jump #start 
nop 

interrupt_vector_table: 


.short 

0x0 01C 

// 

CPU 

.short 

0x0 01C 

// 

CPU 

.short 

0x0 01C 

// 

CPU 

.short 

0x0 01C 

// 

CPU 

.short 

0x0 01C 

// 

IRQ 

.short 

0x0 0IE 

// 

IRQ keyboard 

.short 

0x0 01C 

// 

IRQ 

.short 

0x0 01C 

// 

IRQ 

.short 

0x0 01C 

// 

software 

.short 

0x0 01C 

// 

software 

.short 

0x0 01C 

// 

software 

.short 

0x0 01C 

// 

software 


default_interrupt_routine: 



Version "C": 16-bit little-endian 


781 


iret 


op_code_error: 


stop 


keyboard: 


in 1 

// Keyboard read. 

equal 

jump8z #keyboard_end 

// Exit if no data 
// was read. 

out 0 

// Otherwise print 
// on screen the 
// same value. 

jump #keyboard 

// Loop. 

keyboard_end: 


iret 


start: 


loadl6 #data_l 

// Set the stack 

mv %MDR, %SP 

// 

// location. 

ivtl #interrupt_vector_ 

_table 

imrl OxOF 

// All IRQs are 

seti 

// enabled. 

keyboard_reset: 


in 1 

// Keyboard read. 

equal 

jump8nz #start 

// Loop until the 
// keyboard buffer 
// is empty. 

endless_cycle: 


jump #endless_cycle 

// Just loop 



782 


Version "C": 16-bit little-endian 





// 

forever. 

stop: 



// 

Will never 


stop 


// 

reach this 




// 

point. 

data_0 : 

.short 

0 



data_l: 

.short 

0x0080 



end 






Figure 11.49. Keyboard input and screen output. Video: ogv 
http://www.youtube.com/watch?v=dgIfZHNTedM 





































































































































































































“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


783 

Version "D" 


Chapter 


« 


12.1 General purpose registers. 786 

12.1.1 Module “RANK”. 789 

12.1.2 Modules “D_select” and “Q_select”. 789 

12.2 Module “VRw”. 790 

12.3 Module “RAM” . 793 

12.4 Module “ALU” and related submodules. 796 

12.5 Module “BUS” . 804 

12.6 Module “IRQ”. 805 

12.7 Modules “Dw” . 807 

12.8 Module “IVT”. 809 

12.8.1 Module “DRw”. 810 

12.9 Module “RTC”: real time clock. 812 

12.10 Module “TTY”. 813 

12.11 Module “HDD” . 818 

12.12 Module “CTRL”. 824 

12.12.1 Modules “Fw”. 827 

12.12.2 Module “CLK_CLR” . 829 

12.13 Memory and microcode fields. 830 

12.14 Opcodes . 836 

12.15 Microcode . 872 






















784 Version "D" 

12.16 Macrocode. 929 


This is another version of the project, with more powerful registers 
and a better control-unit. There are two data-busses, each one con¬ 
nected with a different ALU input, but at the moment, the opcode is 
still reduced to 8-bit and there is no space for enough instructions, 
so the ALU continues to depend on registers A and B . The old SEL 
module is not present anymore because the selection work is done 
inside the control-unit. The MDR register is not present for this ver¬ 
sion; instead there is a temporary register TMP and a new C register, 
used as accumulator. 

This version does not access the memory correctly, as some previous 
version do; this fact is evidenced by a lot of warning produced by the 
TKGate simulation. The next version “E” has a different memory 
management, with a new MDR register, but it is very slow compared 
with the current version. 


Attachments 

Description 

attachments/xcpu/xcpu-d. v 

TKGate Yerilog netlist source file. 

attachments/xcpu/xcpu-d.gm 

TKGate microcode and 

macrocode source file. 

attachments/xcpu/xcpu-d- 

terminal.vpd.tcl 

TCL/Tk script related to the termi¬ 
nal module TTY. 









Version "D" 


785 


Figure 12.2. Simple CPU, version “D”: two data-busses and an 
accumulator register. 












































































































































































786 


Version "D" 


12.1 General purpose registers 

The registers are made in a similar way as the previous version, 
but internally there are new modules that can be incremented or 
decremented without restrictions, before or after reading the register. 
There are two types of registers: the following figure shows the two 
external layouts. 

Figure 12.3. 16-bit registers: external appearance. 

| d register content copy 


4 + 4 

C D c 


A t B 

> 4 * 

As:o connection to the 'A " bus 

\ alu l5m connection from the ALU 

\ t 3:0 test for debugging 


+ + + 


C D 

c 

alu 


A 

t 




c o clear 
c i clock 


bus select: 0-A; 1 =B 
C\ bus write 
Q load byte BO: 7:0 
Q load byte Bl: 15:8 
G byte selection: 0=B0; 1=B1 
G rank: 0-8-bit; 1- 16-bit 
G signed: 0-unsigned; 1-signed 
Go:? pre-increment: -S..+7 
Gi pre-increment update 
Gs:i 2 post-increment: -S.. + 7 


connection to the "B" bus 


















Version "D" 


787 


Figure 12.4. 16-bit registers: internal structure. 



A B 


The C and FL registers are made with a slightly different module, 
where the “B” bus connection is named alu and it is only able to 
receive data. 














































































































788 


Version "D" 


Figure 12.5. Alternative 16-bit registers structure. 



A alu 

The control line C 4 (byte selection ) should be zero when C 5 (rank) 
is equal to one (16-bit size); otherwise, it is used to select the byte: 
when writing to the bus, the selected byte from the register is written 
to the bus (to the lower bus side); when reading from the bus, the 
lower byte from the bus is stored to the selected register byte. The 
following sections show the modules responsible for the bit-size re- 






































































































Version "D" 


789 


duction and the byte selection. 

12.1.1 Module "RANK" 


Figure 12.6. Bit-size reduction module: the module RANK and 
its submodules. 



Do 

12.1.2 Modules "D_select" and "Q_select" 

The incoming byte selection module {D_s elect), when Byte is equal 
to zero, does not change the output, so that Do is equal to Di. When 
Byte is equal to one, the low input byte is replicated to the high 
output byte; that is: Do is equal to Di 7: o-2*+Di 7: o. This alteration is 
used only to copy the byte received from the bus to the selected 
position inside the register. 

The outgoing byte selection (module Q_select ) is used to select from 
the register a byte to be written to the data-bus. When Byte is equal 

























































790 


Version "D" 


to zero, there is no change to the output. When Byte is equal to one, 
the byte Di 15:8 is copied to the byte Do 7: o {Do = Di 15:8 -2*+Di 15:8 ). 
The module RANK does the rest of the work, cleaning the most 
significant byte or setting it if the value is negative and it is to be 
treated as a signed value. 


Figure 12.7. Left side: incoming byte selection. Right side: out¬ 
going byte selection. 


Di 



■< Byte 


Qi 

V 



/ ^ 

/ 

16 


00 o 
u6 



/ 


16 


v 

Qo 


Qi 

Q_select 

Byte 

Qo 



1 0 


/ 8 


-<Byte 


The most important module inside the general purpose register is 
VR8 {versatile register ), which is a 8-bit data register, shown inside 
the figures of the following section. 


12.2 Module "VRw 


The module VRn is n -bit register that allows to add a value, positive 
or negative, before reading the register or after reading it. In partic¬ 
ular, if the value is added before reading, the register might not be 
updated with it, when the clock signal reaches the edge. 



































Version "D" 


791 


Figure 12.8. Module VR8 : how it works. 



It all starts from module VR1 which is made of a D flip-flop and two 
full adders, as shown in the following figure. 































792 


Version "D 


Figure 12.9. Module VR1. 



Two modules VR1 make a module VR2 ; two modules VR2 make a 
module VR4 and so on. 














Version "D" 


793 


Figure 12.10. Modules VR2 and VR4. 



12.3 Module "RAM 


The module RAM is similar to the previous version of the project. 
In particular, there is now the ability to receive an address from the 
TMP register and, when the memory is written, there are two added 
D latches (modules DH8 ) which hold the data read from the bus. 







































































































794 


Version "D" 


Figure 12.11. The RAM module. 



Modules DHn are the same as the previous version, starting from a 
controlled NAND SR latch, which becomes a D latch, as the follow¬ 
ing figure shows. 





























































































Version "D" 


795 


Figure 12.12. The steps from the SR latch to the DH4 module. 


D 

V 



Q 

































































































796 Version "D" 

12.4 Module "ALU" and related submodules 


The module ALU , is similar to the previous version; the most im¬ 
portant difference is that there is a single set of ALU status flags: 
carry , zero , negative , overflow. The ALU module contains the same 
module RANK already seen inside the general purpose registers. 


Figure 12.13. Module ALU. 



The other components inside the ALU module are just the same as 
the previous version. 













































































































































Version "D" 


797 


Figure 12.14. Module LOGIC : the logic unit. 













































798 


Version "D" 


Figure 12.15. Module AS: addition and subtraction 













































Version "D" 


799 


Figure 12.16. Modules FAn : w-bit full adder. 



V 

S 


<Ci 


<03 








































































sh _left_and_carry_left_16 


800 


Version "D" 


Figure 12.17. Module SH: bit shift. 



6 


U 






la [ 

D 1 

Ir 

Lo 


Li 


SH8 


Ri 


Ro 

C 

) 

c 






6 


la 

D 

Ir 


Lo 

SH8 

Li 

◄- 

Ri 



Ro 

-► 

C 

) 


S 



sh left and carry loft 8 


/ 8 


use_previous_carry 


□ 


<ZF- 


-<Ci 


sh_right_and_carry_right 


D 


Y | 

Col 6 016 


I 

S 


Y 

08 


V 

Co8 


<C 






































































Version "D" 


801 


Figure 12.18. Module ROT : bit rotation. 



The modules SHn are one-bit logic or arithmetic shifter. It all starts 
from module SHI , as the following figure shows. 























































802 


Version "D" 


Figure 12.19. Module SHn : one-bit logic or arithmetic shift. 



[1] Arithmetic shift conditions: 

- the requested shift is arithmetic; 

- the requested shift is to the right; 

- the most significant bit value is one. 

[2] Overflow conditions: 

- the requested shift is arithmetic; 

- the requested shift is to the left; 

- the most significant bit value is changed. 


la 

V 


D 

V 


//2 module SH2 


Lo 


Ri >- 


r 


V 

o 


la 

v 


Lo 


Ri >- 


o 


J 


A) 2 
s 


D 

V 



/ . 

/ 

4 


module SH4 


4 

/ / Z 


rt2 
ro o 


lr 

V 



1; 

a 

D 

lr 


la 

D 

lr 

◄- 

Lo 


SHI 

Li 

◄- 

◄- 

Lo 

SHI 

Li 

-► 

Ri 



Ro 

-► 

-► 

Ri 


Ro 


0 


S 



0 


S 


lr 

v 


I; 

a D lr 


la D lr 


Lo 

Li 

◄- ◄- 

Lo Li 

4- 


SH2 


SH2 


Ri 

Ro 

-► -► 

Ri Ro 

-► 

C 

) S 


0 S 



— <Li 
->■ Ro 


—<Li 
->■ Ro 

























































































Version "D" 


803 


c> 


Figure 12.20. Module FSR : flags set-reset. 


Fi 

V 



V 

Fo 










































































804 

12.5 Module "BUS 


Version "D 


« 


The module BUS is used to let the control unit put a value inside 
the data-bus. This module BUS is almost the same as the previous 
version: only the connection names to the bus are changed and the 
control line used to select the destination bus. 

Figure 12.21. Module BUS. 


bus write 


bus select 



1 o 



y 

B 


y 

A 


























Version "D" 


805 


12.6 Module "IRQ" 

The IRQ module is just the same as the previous version, but here is 
connected to the A data-bus. All the details about the module func¬ 
tionality should be found at the previous version description. 


■ irq_register 


806 


Version "D" 


Figure 12.22. Module IRQ. 























































































































































Version "D" 


807 


12.7 Modules "Dn" 

The modules Dn are D flip-flops, in parallel, as the following figure 
shows. 


808 


Version "D" 


Figure 12.23. Building Dn modules. 


p > 


Ck > 


D > 


C > 



Q 


Q 
















































































































































Version "D" 


809 


12.8 Module "IVT" 

The IVT module is just the same as the previous version, but here is 
connected to the A data-bus. All the details about the module func¬ 
tionality should be found at the previous version description. 

Figure 12.24. Module IVT. 











































Version "D" 


810 

12.8.1 Module "DRw 


The modules IRQ and IVT use modules DRn , which are n -bit data 
registers. 


Version "D" 


811 


Figure 12.25. Building DR n modules. 


D 

V 



Q 














































































812 

12.9 Module "RTC": real time clock 


Version "D" 


The RTC module (real time clock ) is just the same as the previous 
version: it generates a 1 Hz impulse, producing the hardware inter¬ 
rupt IRQO. All the details about the module functionality should be 
found at the previous version description. 


Listing 12.26. Module RTC : Verilog declaration. 


module RTC (T); 


output T; 


reg p; 


always 


begin 


p = 0; 


$tkg$wait 

(500) ; 

P = i; 


$tkg$wait 

(500); 

end 


assign T = p; 


endmodule 




Version "D" 


813 


12.10 Module "TTY" 

The TTY module is just the same as the previous version: it is a 
textual screen-keyboard terminal interface. All the details about the 
module functionality should be found at the previous version de¬ 
scription. 


Figure 12.27. Module TTY. 


























































































































rtj 


14 


Version "D 


Listing 12.28. Module terminal : Verilog code. 

module terminal(K_DATA, K_REQ, K_ACK, 

S_REQ, S_ACK, CLR); 

output K_ACK; 
output S_ACK; 
output [7:0] K_DATA; 
input [7:0] S_DATA; 
input K_REQ; 
input S_REQ; 
input CLR; 
reg k_ready; 
reg [7:0] key; 
reg s_ready; 

initial 

begin 

k_ready = 0; 
s_ready = 0; 
key = 0; 
end 

always 

begin 

@(posedge CLR) 
k_ready = 0; 
s_ready = 0; 
key = 0; 
end 


S_DATA, 



Version "D 


initial $tkg$post("TERMINAL", 

always 

begin 

@ (posedge K_REQ); 

# 5; 

key = $tkg$recv("%m.KD") ; 

# 5; 

k_ready = 1'b1; 

# 5; 

@ (negedge K_REQ); 

# 5; 

k_ready = 1'bO; 
end 

always 

begin 

@ (posedge S_REQ); 

# 5; 

$tkg$send("%m.SD",S_DATA) 

# 5; 

s_ready = l'bl; 

# 5; 

@ (negedge S_REQ); 

# 5; 

s_ready = 1'bO; 
end 


assign S_ACK = s_ready; 




816 


Version "D" 


assign K_DATA = key; 
assign K_ACK = k_ready; 

endmodule 


Listing 12.29. File ‘share/tkgate/vpd/terminal. tel’ for 

TCL interface. _ 

image create bitmap txteurs -file "$bd/txtcurs.b" 

VPD::register TERMINAL 
VPD::allow TERMINAL::post 
VPD::allow TERMINAL::data 

namespace eval TERMINAL { 

# Public variables declarations: the variables $terminal_... 

# are arrays of which only the element $n is used; 

# that element identifies uniquely the working interface instance. 

variable terminal_w 
variable terminal_pos 

# 

variable KD 

# Function requested by TKGate to create the interface. 

proc post {n} { 

variable terminal_w 
variable terminal_pos 

# Create the window and save the object element in a $terminal_w array element. 

set terminal_w($n) [VPD::createWindow "TERMINAL $n" -shutdowncommand "TERMINAL::unpost $n" ] 

# For convenience, copy the object reference inside the local 

# variable $w; then, the variable $w will be used as a reference to the object. 

set w $terminal_w($n) 
text $w.txt -state disabled 
pack $w.txt 

# Put the cursor at the end of the displayed text. 

$w.txt image create end -image txteurs 

# Bind the keyboard input, related to the object represented by 

# $terminal_w ($n), to the function sendChar. 

bind $w <KeyPress> "TERMINAL::sendChar $n \"%A\"" 

# Open a reading channel, named «SD» (screen data), 

# and associate it to the function «data»; moreover, open a 

# writing channel, named «KD» (keyboard data). 

if {[info exists ::tkgate_islnitialized]} { 

VPD::outsignal $n.KD TERMINAL::KD($n) 

VPD::insignal $n.SD -command "TERMINAL::data $n" -format %d 

} 

# Reset the character count, used to count the characters displayed 

# on screen. 

set terminal_pos($n) 0 





Version "D" 


817 


} 

# Function that receives the typing and put It Into the 

# channel «KD», related to the current Interface Instance. 

proc sendChar {n key} { 
variable KD 

if { [string length $key ] == 1 } { 
binary scan $key c c 
set TERMINAL::KD($n) $c 

} 

} 

# Function that TKGate requires to destroy the Interface. 

proc unpost {n} { 

variable terminal_w 
variable terminal_pos 
destroy $terminal_w($n) 
destroy $terminal_pos($n) 
unset terminal_w($n) 
unset terminal_pos($n) 

} 

# Function used to get the data to display on screen. 

proc data {n c} { 

variable terminal_w 
variable terminal_pos 

# For convenience, copy the object reference representing the 

# Interface, Inside the variable $w. 

set w $terminal_w($n) 
catch { 

# The variable $c contains the character to display. 

if { $C == 7 } { 

# BEL 

bell 

return 

} elseif { $c == 127 | | $c == 8 } { 

# DEL I BS 

if { $terminal_pos($n) > 0 } { 

# Delete the last displayed character, but only If the 

# characters counter Is greater than zero, otherwise 

# the cursor would disappear and the next characters 

# would be located In an Invisible screen area. 

$w.txt configure -state normal 
$w.txt delete "end - 3 chars" 

$w.txt see end 

$w.txt configure -state disabled 

set terminal_pos($n) [expr {$terminal_pos($n) - l}] 

} 

return 

} elseif { $c == 13 } { 

# Convert CR to LF. 

set c 10 

} 

# Convert the character number Into a visible symbol. 

set x [format %c $c] 



818 


Version "D" 


# Display the symbol . 

$w.txt configure -state normal 
$w.txt insert "end - 2 chars" $x 
$w.txt see end 

$w.txt configure -state disabled 

# Update the displayed characters counter. 

set terminal_pos($n) [expr {$terminal_pos($n) + l}] 

} 

} 

} 


12.11 Module "HDD" 

The HDD module is just the same as the previous version: it is a 
simulated mass-memory drive with the ability to handle eight units. 
All the details about the module functionality should be found at the 
previous version description. 



Version "D" 


819 


Figure 12.30. Module HDD. 



A 


Listing 12.31. Verilog code describing the module hd. 


module 

hd(DRIVE, SECTOR, 

BYTE, 

WRITE, DATA_IN, 


DATA_OUT, REQ, 

ACK, 

CLR) ; 

input 

[2:0] DRIVE; 



input 

WRITE, REQ, CLR; 



input 

[15:0] SECTOR; 



input 

[9:0] BYTE; 



input 

[7:0] DATA_IN; 



















































































































820 


Version "D" 


output [7:0] DATA_OUT; 
output ACK; 

// 

integer _data_out; 
integer _ack; 

// 


reg [7:0] buffer[0:1023]; 
reg [8*24-1:0] filename = 

// 


integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

// 


i; 

sector_8; 
sector_7 ; 
sector_6; 
sector_5; 
sector_4 ; 
sector_3; 
sector_2; 
sector_l ; 
sector_0; 
x; 


n hd0_sector_000000000.mem"; 


initial 

begin 

for (i=0; i<1024; i=i+l) 
begin 

// 

// Initial buffer reset with 00. 

// 


buffer[i] = 8'h00; 

end 

ack = 0; 



Version "D" 


821 




822 


Version "D" 


sector_3 - x%10; 
x = x /10; 
sector_4 - x%10; 
x = x /10; 
sector_5 = x%10; 
x = x /10; 
sector_6 = x%10; 
x = x /10; 
sector_7 - x%10; 
x = x /10; 
sector_8 = x%10; 

// 

// The string starts from the right side and 
// continues to the left! 

// 


filename[12*8+7 

: 12 * 

8] 

= sector 

_8 

+ 

8'd48; 

filename[11*8+7 

: 11* 

8] 

= sector 

_7 

+ 

• s. 

00 

T5 

00 

filename[10*8+7 

: 10* 

8] 

= sector 

_6 

+ 

• s. 

00 

00 

filename[9*8+7: 

9*8] 

= 

sector_5 

+ 

8' 

d4 8; 

filename[8*8+7: 

8*8] 

= 

sector_4 

+ 

8' 

d4 8 ; 

filename[7*8+7 : 

7*8] 

= 

sector_3 

+ 

8' 

d4 8 ; 

filename[6*8+7 : 

6*8] 

= 

sector_2 

+ 

8' 

d4 8 ; 

filename[5*8+7 : 

5*8] 

= 

sector_l 

+ 

8' 

d4 8 ; 

filename[4*8+7 : 

4*8] 

= 

sector_0 

+ 

8' 

d4 8 ; 

// 







filename[21*8+7 

: 21* 

8] 

= DRIVE • 

+ 8 

' d.4 8 ; 


// 

if (WRITE) 
begin 

// 

// Put data inside the buffer. 



Version "D" 


823 


// 

buffer[BYTE] = DATA_IN; 

// 

// Save the buffer to disk. 

// Please remember that $writememh() 

// must be enabled inside 
// TKGate configuration! 

// 

$writememh(filename, buffer); 

// 

// Return the same data read. 

// 

_data_out = buffer[BYTE]; 
end 
else 
begin 

// 

// Get data from disk to the buffer. 

// 

$readmemh(filename, buffer); 

// 

// Return the data required. 

// 

_data_out = buffer[BYTE]; 
end 

// 

// Acknowledge. 

// 

_ack = 1; 

// 

// Wait the end of request (the negative edge) 



824 


Version "D" 


// before restarting the loop. 
// 

@(negedge REQ); 

# 10 ; 

// 

// Now become ready again. 

// 

_ack = 0; 
end 

// 

assign DATA_0UT = _data_out; 
assign ACK = _ack; 

// 

endmodule 


12.12 Module "CTRL" 

The module CTRL is more complex than the previous version, be¬ 
cause the conditional jumps are now managed inside the control 
module and because that requires the ability to jump inside the mi¬ 
crocode execution. 



Version "D" 


825 


Figure 12.32. Module CTRL. 



The microprogram counter, /iPC, is made with a module VR10 , but 
connected in the way that it is incremented at every positive clock 
edge. The \iPC can load a new address when the load line is acti¬ 
vated, or when the jumpjrue line is active. The microcode Jump 
line contains a microcode address to jump to, when jumpjrue is 
active. The condition_select line contains a number, representing 
the condition to be checked, so that, if true, it will activate the line 































































































































Version "D" 


826 


jump_true . 

Figure 12.33. Module CTRL : microcode load selection. 



condition select 


The previous figure shows the detail of the upper side, where there 
is the selection control of the microcode address to load inside the 
/iPC. The microcode address might come: 











































































Version "D" 827 

• from the map memory, as a translation of the opcode into mi¬ 
crocode address; 

• from the dip-switch containing the address of the microcode pro¬ 
cedure necessary to handle a hardware interrupt (IRQ); 

• from the line microcode Jump . 

When no other special conditions is present and the line load is ac¬ 
tive, the register /iPC loads the value obtained from the map mem¬ 
ory. If a hardware interrupt was previously received while hardware 
interrupts were allowed, it is stored inside the D flip-flop on the right. 
Then, when the control unit tries to load the next opcode address, it 
loads the interrupt procedure address instead. The condition_select 
and the microcode Jump lines are controlled by the microcode: this 
way the jump that is selected is done only if the condition results 
true, otherwise, there is no jump and the register fiPC is simply in¬ 
cremented to the next microinstruction. 

The control unit contains also the clock generator and a frequency 
divisor, as described in the following sections. 

12.12.1 Modules "Fw" 

The modules Fn are frequency divisors, made with T flip-flop, as 
the following figures show. 


828 


Version "D" 


Figure 12.34. Modules D1 and 77: building a T flip-flop from a 
D flip-flop. 

module Dl: positive edge D flip-flop p y module Tl: Tflip-flop 



Figure 12.35. Building the F n modules. 

module FI 



A 

C 


























































































































Version "D" 


829 


12.12.2 Module "CLK_CLR" 

The module CLKJCLR is responsible for the clock pulse generation 
and for the reset line, which is to be synchronized with the clock. The 
clock frequency may be controlled by the dip-switch at the top. It is 
important to recall that the control unit receives an inverted clock 
pulse, because the microcode data should be ready before the clock 
positive edge. 


Figure 12.36. Module CLKJCLR. 





































































830 


Version "D" 


Figure 12.37. Module onejup , used to start the oscillation inside 
the module CLK_CLR. 

module one_up #(.W(1000)) (Z) ; 

output Z; 
reg Z; 

initial 

begin 

Z = 1'bO; 

$tkg$wait (W); 

Z = l'bl; 
end 

endmodule 

12.13 Memory and microcode fields 

The memory for this version of the project is described by the fol¬ 
lowing lines of TKGate code. There are many blocks of memory 
for the microcode word, because every component connected to the 
data-bus can be controlled independently. 



Version "D" 


831 


Listing 12.38. Memory banks description for TKGate. 


map 


bank [9:0] 


microcode 

microcode 

microcode 

microcode 

microcode 

microcode 

microcode 

microcode 

macrocode 


bank[31:0] 
bank[63:32] 
bank [95:64] 
bank [127:96] 
bank [159:128] 
bank [191:160] 
bank[223:192] 
bank [255:224] 
bank [15:0] 


Ctrl .map; 
Ctrl .microO; 
Ctrl .micro1; 
Ctrl .micro2; 
Ctrl .micro3; 
Ctrl .micro4; 
Ctrl .micro5; 
Ctrl .micro6; 
Ctrl .micro7; 
ram.ram; 


Listing 12.39. Fields of the microcode word, for TKGate. 


field 

Ctrl[1:0] 

= {nop=0, stop=l, load=2}; 


field 

j ump[5:2] 

= {false=0, carry_t=l, zero_t=2, negative_t=3. 



overflow_t=4, irq_enabled_t=5, true 

= 6, 



carry_f=9, zero_f=10, negative_f=11 
overtlow_f=12, irq_enabled_f=13 }; 

r 

field 

addr[15:6] 

o' 

II 

o 

■H 

II 


// 




field 

ir[31:16] 

= {select_bus_a=0, select_bus_b=l, bus. 

_write=2 r 



register_load_byte_l=4, register_load_byte_2=8. 



register_load=12, 

select_byte_1 = 0 f select_byte_2 = l6, 




rank_8 = 0 , rank_16=32, unsigned=0, signed=64. 



qpl=0x0080, qp2=0x0100, qp3=0x0180. 

qp4=0x0200. 



qp5=0x0280, qp6=0x0300, qp7=0x0380. 

qm8=0x0400. 



qm7=0x0480, qm6=0x0500, qm5=0x0580. 

qm4=0x0 60 0 , 



qm3=0x0680, qm2=0x0700, qml=0x0780. 

qup=0x0800. 



dpl=0xl000, dp2=0x2000, dp3=0x3000. 

dp4=0x4000. 



dp5=0x5000, dp6=0x6000, dp7=0x7000. 

dm8=0x8000. 



dm7=0x9000, dm6=0xA000, dm5=0xB000, 

dm4=0xC000, 



dm3=0xD000, dm2=0xE000, dml=0xF000 

}; 

// 




field 

ram[37:32] 

= {select_bus_a=0, select_bus_b=l, bus. 

_write=2 r 



load=4, p=0, i=8, j=16, s=24, t=32} 

r 




832 


Version "D" 


// 






field 

pc[53:38] 

= {select_bus_a 

=0, selects 

bus_b “1^ bus. 

_write=2, 



register_load_byte_l=4, 

register_load_byte_2=8 , 



register_load=12 , 





select_byte_ 

.1=0, select 

_byte_2=16. 




rank_8=0, rank_16=32, unsigned=0, signed=64. 



qp1=0x0080, 

qp2=0x0100. 

qp3=0x0180, 

qp4=0x0200, 



qp5=0x0280. 

qp6=0x0300, 

qp7=0x0380. 

qm8=0x0400. 



qm7=0x0480. 

qm6=0x0500, 

qm5=0x0580, 

qm4=0x0600. 



qm3=0x0680. 

qm2=0x0700. 

qml=0x0780. 

qup=0x0800. 



dp1=0x1000, 

dp2=0x2000. 

dp3=0x3000, 

dp4=0x4000. 



dp5=0x5000, 

dp6=0x6000. 

dp7=0x7000. 

dm8=0x8000. 



dm7=0x9000, 

dm6=0xA000, 

dm5=0xB000, 

dm4=0xC000, 



dm3=0xD000, 

dm2=0xE000, 

dml=0xF000 

}; 

field 

i[69:54] 

= {select_bus_a 

=0, selects 

bus_b bus. 

_write=2, 



register_load_byte_l=4 , 

register_load_byte_2=8 , 



register_load=12 , 





select_byte_ 

.1=0, select 

_byte_2=16. 




rank_8=0, rank_16=32, unsigned=0, signed=64. 



qpl=0x0080, 

qp2=0x0100, 

qp3=0x0180. 

qp4=0x0200. 



qp5=0x0280. 

qp6=0x0300, 

qp7=0x0380. 

qm8=0x0400. 



qm7=0x0480. 

qm6=0x0500. 

qm5=0x0580. 

qm4=0x0 60 0, 



qm3=0x0680, 

qm2=0x0700. 

qml=0x0780. 

qup=0x0800. 



dp1=0x1000, 

dp2=0x2000. 

dp3=0x3000, 

dp4=0x4000. 



dp5=0x5000, 

dp6=0x6000. 

dp7=0x7000. 

dm8=0x8000. 



dm7=0x9000, 

dm6=0xA000, 

dm5=0xB000, 

dm4=0xC000, 



dm3=0xD000, 

dm2=0xE000, 

dml=0xF000 

}; 

field 

j[85:70] 

= {select_bus_a 

=0, selects 

bus_b=l, bus. 

_write=2, 



register_load_byte_l=4, 

register_load_byte_2=8. 



register_load=12, 





select_byte_ 

.1=0, select 

_byte_2=16. 




rank_8=0, rank_16=32, unsigned=0, signed=64. 



qpl=0x0080. 

qp2=0x0100, 

qp3=0x0180, 

qp4=0x0200. 



qp5=0x0280. 

qp6=0x0300, 

qp7=0x0380. 

qm8=0x0400. 



qm7=0x0480. 

qm6=0x0500. 

qm5=0x0580. 

qm4=0x0 60 0, 



qm3=0x0680. 

qm2=0x0700. 

qml=0x0780. 

qup=0x0800. 



dpl=0xl000. 

dp2=0x2000. 

dp3=0x3000, 

dp4=0x4000. 



dp5=0x5000. 

dp6=0x6000. 

dp7=0x7000. 

dm8=0x8000. 



dm7=0x9000. 

dm6=0xA000, 

dm5=0xB000, 

dm4=0xC000, 



dm3=0xD000, 

dm2=0xE000, 

dml=0xF000 

}; 



Version "D 


£ 


field sp[101:86] = {select_bus_a~0^ select_bus_b = 1^ bus_write=2, 

register_load_byte_l=4 , register_load_byte_2=8, 
register_load=12, 

select_byte_l=0 , select_byte_2=l6, 
rank_8=0, rank_16=32, unsigned=0, signed=64, 
qpl=0x0080, qp2=0x0100, qp3=0x0180, qp4=0x0200, 
qp5=0x0280, qp6=0x0300, qp7=0x0380, qm8=0x0400, 
qm7=0x0480, qm6=0x0500, qm5=0x0580, qm4=0x0600, 
qm3=0x0680, qm2=0x0700, qml=0x0780, qup=0x0800, 
dpl=0xl000, dp2=0x2000, dp3=0x3000, dp4=0x4000, 
dp5=0x5000, dp6=0x6000, dp7=0x7000, dm8=0x8000, 
dm7=0x9000, dm6=0xA000, dm5=0xB000, dm4=0xC000, 
dm3=0xD000, dm2=0xE000, dml=0xF000 }; 
field tmp[117:102] = {select_bus_a=0, select_bus_b=l, bus_write=2, 

register_load_byte_l=4 , register_load_byte_2 = 8, 
register_load=12, 

select_byte_l=0, select_byte_2=l6, 
rank_8=0, rank_16=32, unsigned=0, signed=64, 
qpl=0x0080, qp2=0x0100, qp3=0x0180, qp4=0x0200, 
qp5=0x0280, qp6=0x0300, qp7=0x0380, qm8=0x0400, 
qm7=0x0480, qm6=0x0500, qm5=0x0580, qm4=0x0600, 
qm3=0x0680, qm2=0x0700, qml=0x0780, qup=0x0800, 
dpl=0xl000, dp2=0x2000, dp3=0x3000, dp4=0x4000, 
dp5=0x5000, dp6=0x6000, dp7=0x7000, dm8=0x8000, 
dm7=0x9000, dm6=0xA000, dm5=0xB000, dm4=0xC000, 
dm3=0xD000, dm2=0xE000, dml=0xF000 }; 
field fl[133:118] = {select_bus_a=0, select_bus_b=l, bus_write=2, 

register_load_byte_l=4 , register_load_byte_2 = 8, 
register_load=12 , 

select_byte_l=0, select_byte_2=l6, 
rank_8=0, rank_16=32, unsigned=0, signed=64, 
qpl=0x0080, qp2=0x0100, qp3=0x0180, qp4=0x0200, 
qp5=0x0280, qp6=0x0300, qp7=0x0380, qm8=0x0400, 
qm7=0x0480, qm6=0x0500, qm5=0x0580, qm4=0x0600, 
qm3=0x0680, qm2=0x0700, qml=0x0780, qup=0x0800, 
dpl=0xl000, dp2=0x2000, dp3=0x3000, dp4=0x4000, 
dp5=0x5000, dp6=0x6000, dp7=0x7000, dm8=0x8000, 
dm7=0x9000, dm6=0xA000, dm5=0xB000, dm4=0xC000, 
dm3=0xD000, dm2=0xE000, dml=0xF000 }; 

= {select_bus_a=0, select_bus_b=l, bus_write=2. 


field c[149:134] 




834 


Version "D" 


// 

field alu[158:150] 


// 

field a[174:159] 


field b[190:175] 


register_load_byte_l=4, register_ 
register_load=12, 

select_byte_l=0, select_byte_2=l6 
rank_8=0, rank_16=32, unsigned=0, 
qpl=0x0080, qp2=0x0100, qp3=0x018 
qp5=0x0280, qp6=0x0300, qp7=0x038 
qm7=0x0480, qm6=0x0500, qm5=0x058 
qm3=0x0680, qm2=0x0700, qml=0x078 
dpl=0xl000, dp2=0x2000, dp3=0x300 
dp5=0x5000, dp6=0x6000, dp7=0x700 
dm7=0x9000, dm6=0xA000, dm5=0xB00 
dm3=0xD000, dm2=0xE000, dml=0xF00 


load_byte_2=8, 


signed=64, 

0, qp4=0x0200, 
0, qm8=0x0400, 
0, qm4=0x0600, 
0, qup=0x0800, 
0, dp4=0x4000, 
0, dm8=0x8000, 
0, dm4=0xC000, 
0 }; 


{unsigned=0, signed=l, rank_8=0 , rank_16=2, 

a=0, and=4, or=8, xor=12 , 
nxor=16, nor=20, nand=24, not=28, 
add=64, sub=68, addc=72, subb=76, 
lshl=12 8 r lshr=132, ashl=136, ashr=140, 
rotcl=144, rotcr=14 8, 
rot1=192, rotr=l96, 

clearc=256 , clearz=260, clearn=264 , 
clearo=2 68, cleari=272, 
setc=288, setz=292, setn=296, 
seto=300, seti=304}; 


{select_bus_a=0 , select_bus_b=l, bus_write=2, 
register_load_byte_l = 4 , register_load_byte_2 = 8 
register_load=12, 

select_byte_l=0, select_byte_2=l6, 
rank_8=0, rank_16=32, unsigned=0, signed=64, 
qpl=0x0080, qp2=0x0100, qp3=0x0180, qp4=0x0200 
qp5=0x0280, qp6=0x0300, qp7=0x0380, qm8=0x0400 
qm7=0x0480, qm6=0x0500, qm5=0x0580, qm4=0x0600 
qm3=0x0680, qm2=0x0700, qml=0x0780, qup=0x0800 
dpl=0xl000, dp2=0x2000, dp3=0x3000, dp4=0x4000 
dp5=0x5000, dp6=0x6000, dp7=0x7000, dm8=0x8000 
dm7=0x9000, dm6=0xA000, dm5=0xB000, dm4=0xC000 
dm3=0xD000, dm2=0xE000, dml=0xF000 }; 
{select_bus_a=0, select_bus_b=l, bus_write=2, 
register_load_byte_l = 4 , register_load_byte_2 = 8 



Version "D" 


835 


field bp[20 6:191] 


// 

field bus[224:207] 

// 

field ioa[240:225] 


// 

field ivt[243:241] 

// 


register_load=12, 

select_byte_l=0, select_byte_2=l6, 
rank_8=0, rank_16=32, unsigned=0, signed=64, 
qpl=0x0080, qp2=0x0100, qp3=0x0180, qp4=0x0200, 
qp5=0x0280, qp6=0x0300, qp7=0x0380, qm8=0x0400 ( 
qm7=0x0480, qm6=0x0500, qm5=0x0580, qm4=0x0600 ( 
qm3=0x0680, qm2=0x0700, qml=0x0780, qup=0x0800, 
dpl=0xl000, dp2=0x2000, dp3=0x3000, dp4=0x4000, 
dp5=0x5000, dp6=0x6000, dp7=0x7000, dm8=0x8000, 
dm7=0x9000, dm6=0xA000, dm5=0xB000, dm4=0xC000, 
dm3=0xD000, dm2=0xE000, dml=0xF000 }; 
{select_bus_a=0, select_bus_b=l, bus_write=2, 
register_load_byte_l=4, register_load_byte_2=8 ( 
register_load=12, 

select_byte_l=0, select_byte_2=l6, 
rank_8=0, rank_16=32, unsigned=0, signed=64, 
qpl=0x0080, qp2=0x0100, qp3=0x0180, qp4=0x0200 ( 
qp5=0x0280, qp6=0x0300, qp7=0x0380, qm8=0x0400 ( 
qm7=0x0480, qm6=0x0500, qm5=0x0580, qm4=0x0600 ( 
qm3=0x0680, qm2=0x0700, qml=0x0780, qup=0x0800, 
dpl=0xl000, dp2=0x2000, dp3=0x3000, dp4=0x4000, 
dp5=0x5000, dp6=0x6000, dp7=0x7000, dm8=0x8000, 
dm7=0x9000, dm6=0xA000, dm5=0xB000, dm4=0xC000 ( 
dm3=0xD000, dm2=0xE000, dml=0xF000 }; 


{bw=0x!0000, select_bus_a=0, select_bus_b=0x20000}; 


{select_bus_a=0, select_bus_b=l, bus_write=2, 
register_load_byte_l=4, register_load_byte_2=8, 
register_load=12, 

select_byte_l=0, select_byte_2=l6, 
rank_8=0, rank_16=32, unsigned=0, signed=64, 
pl=128, p2=256, p3=384, p4=512, 
p5=640, p6=768, p7=896, 

m8=1024, m7=1152, m6=1280, m5=1480, m4=1536, 
m3=1664, m2=1792, ml=1920, update=2048}; 


{bus_write=l, ivt_load=2, 
select_int_a=0, select_int_b=4}; 



836 


Version "D" 


field irq[246:244] = {bus_write=l, irq_mask_load=2, irq_done=4}; 

// 

field ioc[250:247] = {load=l, bus_write=2, req=4, isack=8}; 


12.14 Opcodes 

Only eight bits are used for the opcodes and all the available combi¬ 
nations are specified. The following table shows the opcode organi¬ 
zation. 

Table 12.40. Opcodes. 


0x60 

0x68 

0x70 

0x78 

0x80 

0x81 

0x82 

0x84 

0x86 

0x88 


0x00 

00. 

0x40 

010000 .. 

0x44 

010001 .. 

0x48 

010010 .. 

0x4C 

0100110. 

0x4E 

0100111. 

0x50 

010100 .. 

0x54 

010101 .. 

0x58 

010110 .. 

0x5C 

0101110. 

0x5E 

0101111. 


01100 ... 
01101 ... 
OHIO. . . 
01111 ... 
10000000 
10000001 
1000001 . 
1000010 . 
1000011 . 
1000100 . 


byte 0 


byte 1 


byte 2 


b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 


cp % % 

% 

% 

cp n % 

A, B, 1, J 

const16 

cp (%) % 

(U) 

A, B 



cp % (%) 

A, B 

(i. j) 



cp n (%) 

(i. j) 

const16 

cp (%) (%) 

(i. j) 



cp8 n % 

A, B, 1, J 

const8 


cp8 (%) % 

(U) 

A, B 



cp8 % (%) 

A, B 

(i. j) 



cp8 n (%) 

(i. j) 

const8 


cp8 (%) (%) 

(i. j) 






byte 0 




byte 1 

byte 2 

b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 




byte 3 


push % 


push8 % 


pop % 


pop8 % 


% 


% 


% 


% 


push n 


push8 n 


push (%) 


push8 (%) 


pop (%) 


pop8 (%) 


(I. J) 


(I. J) 


(I, J) 


(U) 


byte 3 


const16 


const8 



























































Version "D" 


837 


0x90 

0x98 

0x9A 

0x9C 

0x9E 

OxAO 

0xA2 

0xA4 

0xA6 

0xA8 

OxAA 


Ox AC 
OxAE 
OxBO 
0xB2 
0xB4 
0xB6 
OxB8 


OxBC 

OxBE 

OxCO 

0xC2 

0xC4 

0xC6 

OxC8 

OxCA 

OxCC 

OxCE 


OxDO 

0xD2 

0xD4 

0xD6 

OxD8 

OxDA 

OxDC 


byte 0 _ byte 1 byte 2 byte 3 



b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 


10010 ... 

jump %flag 0|1 #ref 

%flag 

TRUE 

#ref 

1001100. 

equal, not 

NOT 


1001101. 

and 

NOT 


1001110. 

or 

NOT 


1001111. 

xor 

NOT 


1010000. 

add, sub 

sub 


1010001. 

addc, subb 

sub 


1010010. 

Ish 

right 


1010011. 

ash 

right 


1010100. 

rote 

right 


1010101. 

rot 

right 



byte 0 byte 1 byte 2 byte 3 


1010110 . 
1010111 . 
1011000 . 
1011001 . 
1011010 . 
1011011 . 
101110 .. 


byte 0 byte 1 byte 2 byte 3 


1011110 . 

1011111 . 

1100000 . 

1100001 . 

1100010. 

1100011. 

1100100. 

1100101. 

1100110. 

1100111 . 


byte 0 byte 1 byte 2 byte 3 


1101000 . 

1101001. 

1101010. 

1101011 . 

1101100. 

1101101 . 

1101110 . 


b7 b6 b5 b4 b3 b2 bl 

bO 

add8s, sub8s 

sub 

add8cs, sub8bs 

sub 

Ish8ls, Ish8rs 

right 

ash8ls, ash8rs 

right 

rot8cls, rot8crs 

right 

rot8ls, rot8rs 

right 

casts 

sign 


b7 b6 b5 b4 b3 b2 bl 

bO 

equals, nots 

NOT 

ands 

NOT 

ors 

NOT 

xors 

NOT 

adds, subs 

sub 

addes, subbs 

sub 

Ishls, Ishrs 

right 

ashls, ashrs 

right 

rotcls, roters 

right 

rotls, rotrs 

right 


b7 | b6 | b5 | b4 | b3 | b2 | 

bl 

bO 

add8, sub8 

sub 

add8c, sub8b 

sub 

Ish8 

right 

ash8 

right 

rot8c 

right 

rot8 

right 

cast 

sign 

A, B 






Version "D" 


838 


OxDE 

OxDF 

OxEO 

OxEl 

0xE2 

0xE3 

0xE4 

0xE6 

OxE8 

OxEA 

OxEC 

OxEE 

OxFO 

OxFl 


0xF2 

0xF4 

0xF6 

OxF8 

OxFA 

OxFC 

OxFE 

OxFF 


11011110 

11011111 

11100000 

11100001 

11100010 

11100011 

1110010. 

1110011 . 

1110100. 

1110101 . 

mono. 

1110111 . 

11110000 

11110001 


1111001 . 

1111010 . 

1111011 . 

1111100 . 

1111101 . 

1111110 . 

11111110 

11111111 


byte 0 


b7 b6 b5 b4 b3 b2 bl bO 


call 


return 


byte 1 


byte 2 


byte 3 


#ref 


int 

int 


iret 



imrl 

mask 



ivtl 

#ref 


flag i 0|1 

set 



flag c 0|1 

set 



in n % 

A, B 

port 


in n (%) 

(U) 

port 

out % n 

A, B 

port 

out (%) n 

(i. j) 

port 

if ackjump 

port 

#ref 

if ack call 

port 

#ref 

byte 0 

byte 1 byte 2 byte 3 

b7 b6 b5 b4 b3 b2 bl 

bO 


cmpr, testr 

test 

cmpi, testi 

test 

cmps, tests 

test 

cmp8i, test8i 

test 

cmp8s, test8s 

test 

call (%) 

1, J 



jump 

#ref 


stop 




Table 12.41. Macrocode syntax. 


Macrocode syntax 

Description 

nop 

Not operate. 

cp %src, %dst 

Copy the src register content in¬ 
side the dst register. Allowed reg¬ 
isters are: I, J, A, B, BP, SP, C, 

FL . 

cp nl6, %dst 

Assign a 16-bit constant to a reg¬ 
ister. Allowed destination registers 
are: I, J, A, B. 

cp (%I %J), %A %B 

Assign to register A or B the 16- 
bit value contained in memory at 
the address already available from 
register / or /. 































































Version "D" 


839 


Macrocode syntax 

Description 

cp %A %B, (%I %J) 

Copy in memory the 16-bit value 
of register A or B, to the location 
represented by the register I or J. 

cp nl6, (%I 

%J) 

Assign in memory the 16-bit con¬ 
stant, to the location represented 
by the register I or J. 

cp (%I) 

Copy the 16-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register J. 

cp (%J) 

Copy the 16-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register I. 

cp8 w#, %dst 

Assign a 8-bit constant to a reg¬ 
ister. Allowed destination registers 
are: /, /, A, B. 

cp8 (%I %J) , %A %B 

Assign to register A or B the 8-bit 
value contained in memory at the 
address already available from reg¬ 
ister / or /. 

cp8 %A %B, (%I %J) 

Copy in memory the 8-bit value of 
register A or B, to the location rep¬ 
resented by the register I or J. 

cp8 (%I 

%J) 

Assign in memory the 8-bit con¬ 
stant, to the location represented 
by the register I or J. 

cp8 (%I) 

Copy the 8-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register J. 




840 


Version "D" 


Macrocode syntax 

Description 

cp8 (%J) 

Copy the 8-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register /. 

push reg 

Push at the top of the stack the 16- 
bit value contained inside the reg¬ 
ister. 

pop reg 

Pop from the stack a 16-bit value 
that is then assigned to the register. 

push8 reg 

Push at the top of the stack the 8- 
bit value contained inside the reg¬ 
ister. 

pop8 reg 

Pop from the stack a 8-bit value 
that is then assigned to the register. 

push nl6 

Push at the top of the stack the 16- 
bit constant. 

push n8 

Push at the top of the stack the 8- 
bit constant. 

push (%I %J) 

Push at the top of the stack the 16- 
bit value contained in memory, at 
the location represented by register 
I or /. 

push (%I %J) 

Push at the top of the stack the 16- 
bit value contained in memory, at 
the location represented by register 
I or/. 

push8 (%I %J) 

Push at the top of the stack the 8- 
bit value contained in memory, at 
the location represented by register 
/ or/. 




Version "D" 


841 


Macrocode syntax 

Description 

pop (%I %J) 

Pop from the top of the stack a 
16-bit value that is then copied at 
the memory location represented 
by register I or J. 

pop8 (%I %J) 

Pop from the top of the stack a 

8-bit value that is then copied at 
the memory location represented 
by register I or J. 

jump %ref 

Jump to the address specified. 

jump %carry | %borrowf_. 

'■ :> | %zero | %negativep_> 

^ j %overflow, ^ 

^ 0 | 1, #ref 

Conditional jump. The first argu¬ 
ment is a pseudo-register that se¬ 
lects the flag; the second argu¬ 
ment means the value that the flag 
should have; the third argument is 
the address where the jump should 
go if the condition is met. 

equal 

C A , updating the flags status 

not 

C < — A , updating the flags status 
(one’s complement). 

and 

C A & B, updating the flags. 

nand 

C ~(A & B), updating the flags. 

or 

C <— A 1 B, updating the flags. 

nor 

C <— ~(A 1 B ), updating the flags. 




842 


Version "D" 


Macrocode syntax 

Description 

xor 

C <— A A B, updating the flags. 

nxor 

C ~(A A B ), updating the flags. 

add 

C A + B, updating the flags, 16- 
bit. 

sub 

C A - B, updating the flags, 16- 
bit. 

addc 

C A + B + carry, updating the 
flags, 16-bit. 

subb 

C 4 — A — B — borrow, updating the 
flags, 16-bit. 

lshl 

C A«l, updating the flags: 

logic shift left, 16-bit. 

lshr 

C A»l, updating the flags: 

logic shift right, 16-bit. 

ashl 

C A<«1, updating the flags: 

arithmetic shift left, 16-bit. 

ashr 

C A»>1, updating the flags: 

arithmetic shift right, 16-bit. 

rotcl 

C rotcl(A), updating the flags: 

rotation left with carry, 16-bit. 

rotcr 

C rotcr(A), updating the flags: 

rotation right with carry, 16-bit. 

rot 1 

C v- rotl(A), updating the flags: 
rotation left, 16-bit. 




Version "D" 


843 


Macrocode syntax 

Description 

rotr 

C <— rotr(A), updating the flags: 
rotation right, 16-bit. 

add8 

C A + B, updating the flags, 8- 
bit. 

sub8 

C A - B, updating the flags, 8- 
bit. 

add8c 

C A + B + carry, updating the 
flags, 8-bit. 

sub8b 

C i — A — B — borrow, updating the 
flags, 8-bit. 

lsh81 

C A«l, updating the flags: 

logic shift left, 8-bit. 

lsh8r 

C A»l, updating the flags: 

logic shift right, 8-bit. 

ash81 

C A<«1, updating the flags: 

arithmetic shift left, 8-bit. 

ash8r 

C A»>1, updating the flags: 

arithmetic shift right, 8-bit. 

rot8cl 

C rot8cl(A), updating the flags: 
rotation left with carry, 8-bit. 

rot8cr 

C rot8cr(A), updating the flags: 
rotation right with carry, 8-bit. 

rot 81 

C rot81(A), updating the flags: 
rotation left, 8-bit. 

rot 8r 

C rot8r(A), updating the flags: 
rotation right, 8-bit. 




844 


Version "D" 


Macrocode syntax 

Description 

cast 0 1 %A %B 

Adapt the register value to 8-bit, 
unsigned or signed, depending on 
the first argument. 

equals 

Read the 16-bit value on top of the 
stack and update the flags. 

not s 

Read the 16-bit value on top of the 
stack and replace it with the one’s 
complement, updating the flags. 

ands 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
AND of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

nands 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
NAND of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

ors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
OR of them, updating the flags, the 
registers A and B are overwritten. 

nors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
NOR of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 




Version "D" 


845 


Macrocode syntax 

Description 

xors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
XOR of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

nxors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
NXOR of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

adds 

Pop two 16-bit values from the top 
of the stack and push the sum of 
them, updating the flags. To do the 
calculation, the registers A and B 
are overwritten. 

subs 

Pop a 16-bit values from the top 
of the stack and put it inside the 
register B ; then pop another 16-bit 
value and put inside the register A ; 
then calculate A-B updating the 
flags and push the result inside the 
stack again. 

addcs 

Pop two 16-bit values from the top 
of the stack and push the sum with 
carry of them, updating the flags. 
To do the calculation, the registers 
A and B are overwritten. 




846 


Version "D" 


Macrocode syntax 

Description 

subbs 

Pop a 16-bit values from the top 
of the stack and put it inside the 
register B\ then pop another 16- 
bit value and put inside the regis¬ 
ter A ; then calculate A -B -borrow 
updating the flags and push the re¬ 
sult inside the stack again. 

lshls 

Pop a 16-bit values from the top of 
the stack and push the logic shift 
left of it, updating the flags. 

lshrs 

Pop a 16-bit values from the top of 
the stack and push the logic shift 
right of it, updating the flags. 

ashls 

Pop a 16-bit values from the top of 
the stack and push the arithmetic 
shift left of it, updating the flags. 

ashrs 

Pop a 16-bit values from the top of 
the stack and push the arithmetic 
shift right of it, updating the flags. 

rotcls 

Pop a 16-bit values from the top of 
the stack and push the rotation left 
with carry of it, updating the flags. 

rotcrs 

Pop a 16-bit values from the top 
of the stack and push the rotation 
right with carry of it, updating the 
flags. 

rotls 

Pop a 16-bit values from the top of 
the stack and push the rotation left 
of it, updating the flags. 




Version "D" 


847 


Macrocode syntax 

Description 

rotrs 

Pop a 16-bit values from the top 
of the stack and push the rotation 
right of it, updating the flags. 

add8s 

Pop two 8-bit values from the top 
of the stack and push the sum of 
them, updating the flags. To do the 
calculation, the registers A and B 
are overwritten. 

sub8s 

Pop a 8-bit values from the top of 
the stack and put it inside the reg¬ 
ister B; then pop another 16-bit 
value and put inside the register A ; 
then calculate A-B updating the 
flags and push the result inside the 
stack again. 

add8cs 

Pop two 8-bit values from the top 
of the stack and push the sum with 
carry of them, updating the flags. 
To do the calculation, the registers 
A and B are overwritten. 

sub8bs 

Pop a 8-bit values from the top 
of the stack and put it inside the 
register B\ then pop another 16- 
bit value and put inside the regis¬ 
ter A ; then calculate A -B -borrow 
updating the flags and push the re¬ 
sult inside the stack again. 

lsh81s 

Pop a 8-bit values from the top of 
the stack and push the logic shift 
left of it, updating the flags. 




848 


Version "D" 


Macrocode syntax 

Description 

lsh8rs 

Pop a 8-bit values from the top of 
the stack and push the logic shift 
right of it, updating the flags. 

ash81s 

Pop a 8-bit values from the top of 
the stack and push the arithmetic 
shift left of it, updating the flags. 

ash8rs 

Pop a 8-bit values from the top of 
the stack and push the arithmetic 
shift right of it, updating the flags. 

rotc81s 

Pop a 8-bit values from the top of 
the stack and push the rotation left 
with carry of it, updating the flags. 

rotc8rs 

Pop a 8-bit values from the top 
of the stack and push the rotation 
right with carry of it, updating the 
flags. 

rot81s 

Pop a 8-bit values from the top of 
the stack and push the rotation left 
of it, updating the flags. 

rot8rs 

Pop a 8-bit values from the top 
of the stack and push the rotation 
right of it, updating the flags. 

casts 0 1 

Pop a 16-bit value from the top 
of the stack and push the same 
value, adapted to 8-bit, unsigned 
or signed, depending on the argu¬ 
ment. 

call #ref 

Call the procedure that starts at the 
argument reference: the registers 
FL and PC are pushed inside the 
stack. 




Version "D" 


849 


Macrocode syntax 

Description 

call (%I 

%J) 

Call the procedure that starts at the 
position contained inside register I 
or J: the registers FL and PC are 
pushed inside the stack. 

return 

Return from a previous call: the 
registers PC and FL are retrieved 
from the stack. 

int n8 

Software interrupt call: the regis¬ 
ters FL and PC are pushed inside 
the stack. 

iret 

Return from an interrupt: the regis¬ 
ters PC and FL are retrieved from 
the stack. 

imrl n8 

Load the IMR: interrupt mask reg¬ 
ister. 

ivtl #ref 

Load the IVT: interrupt vector ta¬ 
ble. The argument is the interrupt 
vector table start address in mem¬ 
ory. 

flag_i 0 

1 

Reset or set the flag that allows the 
hardware interrupts. 

flag_c 0 

1 

Reset or set the carry (borrow) 
flag. 

in n8, %A %B 

Read from the I/O address spec¬ 
ified, a byte that is copied inside 
register A or/?. 

in n8, (%I %J) 

Read from the I/O address speci¬ 
fied, a byte that is copied in mem¬ 
ory, at the address specified by reg¬ 
ister / or /. 




850 


Version "D" 


Macrocode syntax 

Description 

out %A %B, n8 

Write to the I/O address specified, 
a byte that is read from register A 
or B. 

out (%I %J) , ffS 

Write to the I/O address specified, 
a byte that is read from memory, at 
the address specified by register I 
or J. 

ifack_jump w#, %ref 

If the I/O port gives an acknoledge 
report, then jump to the specified 
address. 

ifack_call #ref 

If the I/O port gives an acknoledge 
report, then call the specified pro¬ 
cedure. 

cmpr 

Calculate A-B , updating the flags, 
without modifying the accumula¬ 
tor. 

testr 

Calculate A&B (bitwise AND), 
updating the flags, without modi¬ 
fying the accumulator. 

cmpi 

Load A with the value contained in 
memory at the address represented 
by the register /; load B with the 
value contained in memory at the 
address represented by the regis¬ 
ter J; then calculate A-B , updat¬ 
ing the flags, without modifying 
the accumulator. 




Version "D" 


851 


Macrocode syntax 

Description 

testi 

Load A with the value contained in 
memory at the address represented 
by the register /; load B with the 
value contained in memory at the 
address represented by the regis¬ 
ter J; then calculate A &B (bitwise 
AND), updating the flags, without 
modifying the accumulator. 

cmps 

Read from the top of the stack a 
16-bit value and put it inside the 
register B ; read from the stack, just 
under the previous value, a 16-bit 
value and put it inside the regis¬ 
ter A; then calculate A-B , updat¬ 
ing the flags, without modifying 
the accumulator. 

tests 

Read from the top of the stack a 
16-bit value and put it inside the 
register B ; read from the stack, just 
under the previous value, a 16-bit 
value and put it inside the regis¬ 
ter A; then calculate A&B , updat¬ 
ing the flags, without modifying 
the accumulator. 

cmp8r 

Calculate 8-bit A-B, updating the 
flags, without modifying the accu¬ 
mulator. 

test8r 

Calculate 8-bit A&B (bitwise 
AND), updating the flags, without 
modifying the accumulator. 




852 


Version "D" 


Macrocode syntax 

Description 

cmp8i 

Load 8-bit inside A with the value 
contained in memory at the ad¬ 
dress represented by the register /; 
load 8-bit inside B with the value 
contained in memory at the ad¬ 
dress represented by the register J ; 
then calculate A-B, updating the 
flags, without modifying the accu¬ 
mulator. 

test8i 

Load 8-bit inside A with the value 
contained in memory at the ad¬ 
dress represented by the register /; 
load 8-bit inside B with the value 
contained in memory at the ad¬ 
dress represented by the register J; 
then calculate A&B , updating the 
flags, without modifying the accu¬ 
mulator. 

cmp8s 

Read from the top of the stack a 8- 
bit value and put it inside the reg¬ 
ister B; read from the stack, just 
under the previous value, a 8-bit 
value and put it inside the regis¬ 
ter A; then calculate A-B, updat¬ 
ing the flags, without modifying 
the accumulator. 




Version "D" 


853 


Macrocode syntax 

Description 

test8s 

Read from the top of the stack a 8- 
bit value and put it inside the reg¬ 
ister B ; read from the stack, just 
under the previous value, a 8-bit 
value and put it inside the regis¬ 
ter A; then calculate A&B, updat¬ 
ing the flags, without modifying 
the accumulator. 

stop 

Stop the system. 


Listing 12.42. Registers, flags and opcodes encoded for TKGate. 


registers 1=0, J 

< 

CM 

II 

< 

< 

*—1 

II 

B=3 

, BP=4, SP=5, 

C=6, FL=7 ; 

registers carry= 

0, borrow=0, 

zero=l , 

negative=2, overflow=3; 

//- 

op nop { 






map nop : 
operands { - = 

}; 

// 

°P C P { 

// 

0x00; // 

{ +0=0x00; 

not operate 

}; }; 

00 . = cp 

%, % 

map nop : 

0x00; 

// 

00000000 

= cp 

%I, %I = nop 

map cp_i_j : 

0x01; 

// 

00000001 

= cp 

%I, %J 

map cp_i_a : 

0x02; 

// 

00000010 

= cp 

%I, %A 

map cp_i_b : 

0x03; 

// 

00000011 

= cp 

%I, %B 

map cp_i_bp : 

0x04; 

// 

00000100 

= cp 

%I,%BP 

map cp_i_sp : 

0x05; 

// 

00000101 

= cp 

%I, %SP 

map cp_i_c : 

0x0 6; 

// 

00000110 

= cp 

%I, %C 

map cp_i_fl: 

0x07; 

// 

00000111 

= cp 

%I, %FL 

map cp_j_i : 

0x08; 

// 

00001000 

= cp 

%J, %I 

map nop : 

0x0 9; 

// 

00001001 

= cp 

%J, %J = nop 












854 


Version "D" 


map 

o 

1 

LJ- 

1 

OxOA; 

// 

OOOOIOIO 

= 

cp 

%J, %A 


map 

cp_j_b: 

OxOB; 

// 

OOOOlOll 

= 

cp 

%J, %B 


map 

cp_j_bp 

0 x 0 C; 

// 

OOOOllOO 

= 

cp 

%J, %BP 


map 

cp_j_sp 

OxOD; 

// 

OOOOllOl 

= 

cp 

%J, %SP 


map 

cp_j_c: 

OxOE; 

// 

OOOOlllO 

= 

cp 

%J, %C 


map 

c P_j_fi 

OxOF; 

// 

OOOOllll 

= 

cp 

%J, %FL 


map 

cp_a_i : 

0x10; 

// 

OOOIOOOO 

= 

cp 

%A, %I 


map 

cp_a_j: 

0x11; 

// 

OOOlOOOl 

= 

cp 

%A, %J 


map 

nop: 

0x12; 

// 

OOOIOOIO 

= 

cp 

%A, %A = 

nop 

map 

cp_a_b: 

0x13; 

// 

OOOlOOll 

= 

cp 

%A, %B 


map 

cp_a_bp 

0x14; 

// 

OOOIOIOO 

= 

cp 

%A, %BP 


map 

cp_a_sp 

0x15; 

// 

OOOIOIOI 

= 

cp 

%A, %SP 


map 

cp_a_c: 

0x16; 

// 

00010110 

= 

cp 

%A, %C 


map 

cp_a_f1 

0x17; 

// 

OOOlOlll 

= 

cp 

%A, %FL 


map 

cp_b_i: 

0x18; 

// 

OOOllOOO 

= 

cp 

%B, %I 


map 

cp_b_j : 

0x19; 

// 

OOOllOOl 

= 

cp 

%B, %J 


map 

cp_b_a: 

OxlA; 

// 

OOOllOlO 

= 

cp 

%B, %A 


map 

nop: 

OxlB; 

// 

OOOllOll 

= 

cp 

%B, %B = 

nop 

map 

cp_b_bp: 

: 0 x 1C; 

// 

OOOlllOO 

= 

cp 

%B, %BP 


map 

cp_b_sp: 

: OxlD; 

// 

OOOlllOl 

= 

cp 

%B, %SP 


map 

cp_b_c: 

OxlE; 

// 

OOOllllO 

= 

cp 

%B, %C 


map 

cp_b_f1 

OxlF; 

// 

OOOlllll 

= 

cp 

%B, %FL 


map 

cp_bp_i 

0x20; 

// 

OOIOOOOO 

= 

cp 

%BP, %I 


map 

cp_bp_j 

0x21; 

// 

OOlOOOOl 

= 

cp 

%BP,%J 


map 

cp_bp_a 

0x22; 

// 

OOIOOOIO 

= 

cp 

%BP, %A 


map 

cp_bp_b 

0x2 3; 

// 

OOlOOOll 

= 

cp 

%BP, %B 


map 

nop: 

0x2 4; 

// 

OOIOOIOO 

= 

cp 

%BP, %BP 

= nop 

map 

cp_bp_sp: 0x25; 

// 

OOIOOIOI 

= 

cp 

%BP, %SP 


map 

cp_bp_c: 

: 0x26; 

// 

OOlOOllO 

= 

cp 

%BP, %C 

= nop 

map 

cp_bp_fl: 0x27; 

// 

OOlOOlll 

= 

cp 

%BP, %FL 


map 

cp_sp_i 

0x2 8; 

// 

OOIOIOOO 

= 

cp 

%SP, %I 


map 

cp_sp_j 

0x2 9; 

// 

00101001 

= 

cp 

%SP, %J 


map 

cp_sp_a 

0x2A; 

// 

OOIOIOIO 

= 

cp 

%SP, %A 


map 

cp_sp_b 

0x2B; 

// 

00101011 

= 

cp 

%SP, %B 


map 

cp_sp_bp: 0x2C; 

// 

OOlOllOO 

= 

cp 

%SP, %BP 


map 

nop: 

0x2D; 

// 

OOlOllOl 

= 

cp 

%SP, %SP 

= nop 






Version "D" 


855 


map 

o 

1 

w 

V 

1 

o 


0x2E; 

// 

00101110 

= 

cp 

%SP,%C 

map 

cp_sp_fl: 

0x2F; 

// 

00101111 

= 

cp 

%SP, %FL 

map 

cp_c_i : 


0x30; 

// 

00110000 

= 

cp 

%C, %I 

map 

cp_c_j: 


0x31; 

// 

00110001 

= 

cp 

%C, %J 

map 

cp_c_a: 


0x32; 

// 

00110010 

= 

cp 

%C, %A 

map 

cp_c_b: 


0x33; 

// 

00110011 

= 

cp 

%C, %B 

map 

cp_c_bp 


0x34; 

// 

00110100 

= 

cp 

%C, %BP 

map 

cp_c_sp 


0x35; 

// 

00110101 

= 

cp 

%C, %SP 

map 

nop: 


0x3 6; 

// 

00110110 

= 

cp 

%C, %C = nop 

map 

cp_c_f1 


0x37; 

// 

00110111 

= 

cp 

%C, %FL 

map 

cp_fl_i 


0x38; 

// 

00111000 

= 

cp 

%FL, %I 

map 

cp_fl_j 


0x3 9; 

// 

00111001 

= 

cp 

%FL,%J 

map 

cp_fl_a 


0x3A; 

// 

00111010 

= 

cp 

%FL, %A 

map 

cp_fl_b 


0x3B; 

// 

00111011 

= 

cp 

%FL, %B 

map 

cp_fl_bp: 

0 x 3 C; 

// 

00111100 

= 

cp 

%FL,%BP 

map 

cp_fl_sp: 

0x3D; 

// 

00111101 

= 

cp 

%FL, %SP 

map 

cp_fl_c 


0x3E; 

// 

00111110 

= 

cp 

%FL,%C 

map 

nop: 


0x3F; 

// 

00111111 

= 

cp 

%FL, %FL = nop 

// 





010000. . 

= 

cp 

#, % 

map 

cp_num_i: 

0x4 0; 

// 

01000000 

= 

cp 

#, %I 

map 

cp_num_j: 

0x41; 

// 

01000001 

= 

cp 

#, %J 

map 

cp_num_a: 

0x42; 

// 

01000010 

= 

cp 

#,%A 

map 

cp_num_b: 

0x4 3; 

// 

01000011 

= 

cp 

#, %B 

// 





010001.. 

= 

cp 

(%),% 

map 

cp_mi_a 


0x4 4; 

// 

01000100 

= 

cp 

(%I),%A 

map 

cp_mi_b 


0x4 5; 

// 

01000101 

= 

cp 

(%I),%B 

map 

cp_mj_a 


0x46; 

// 

01000110 

= 

cp 

(%J) , %A 

map 

cp_mj_b 


0x4 7; 

// 

01000111 

= 

cp 

(%J) , %B 

// 





010010.. 

= 

cp 

%, %I 

map 

cp_a_mi : 


0x4 8; 

// 

01001000 

= 

cp 

%A, (%I) 

map 

cp_a_mj : 


0x49; 

// 

01001001 

= 

cp 

%A, (%J) 

map 

cp_b_mi : 


0x4A; 

// 

01001010 

= 

cp 

%B, (%I) 

map 

cp_b_mj : 


0x4B; 

// 

01001011 

= 

cp 

%B, ( %J) 

// 





0100110. 

= 

cp 

#, (%) 

map 

cp_num_mi : 

0x4C; 

// 

01001100 

= 

cp 

#, (%D 

map 

cp_num_mj : 

0x4D; 

// 

01001101 

= 

cp 

#, (%J) 








856 


Version "D" 


// 




0100111. 

= 

cp 

(%) 

map 

cp_mi_mj: 

0x4E; 

// 

01001110 

= 

cp 

(%I) 

map 

cp_mj_mi: 

0 x 4 F; 

// 

01001111 

= 

cp 

(%J) 

// 








operands { 







%1 

,%2 = { 

+0=0x00; 

+0[5:3]=%1; 

+0[2:0]=%2; }; 

#1 

,%2 = { 

+0=0x40; 

+0[1:0]=%2; 

+1 

=#1 [7:0]; +2=#1[15:8]; }; 

(% 

1),%2 = { 

+0=0x44; 

+0[1:1]=%1; 

+0[0:0]=%2; }; 

%1 

, (%2) = { 

+0=0x48; 

+0[1:1]=%1; 

+0[0:0]=%2; }; 

#1 

, (%2) = { 

+0=0x4C; 

+0[0:0]=%2; 

+i 

=#1 [7:0]; +2=#1[15:8]; }; 

<% 

}; 

1) = { 

+0=0x4E; 

+0[0:0]=%1; 

}; 



o 

00 

{ 







// 




010100.. 

= 

cp8 

#,% 

map 

cp8_num_i: 

0x50; 

// 

01010000 

= 

cp8 

#, %I 

map 

cp8_num_j: 

0x51; 

// 

01010001 

= 

cp8 

#, %J 

map 

cp8_num_a: 

0x52; 

// 

01010010 

= 

cp8 

#, %A 

map 

cp8_num_b: 

0x53; 

// 

01010011 

= 

cp8 

#r %B 

// 




010101.. 

= 

cp8 

(%),% 

map 

cp8_mi_a: 

0x54; 

// 

01010100 


cp8 

(%I) , %A 

map 

cp8_mi_b: 

0x55; 

// 

01010101 

= 

cp8 

(%I) , %B 

map 

cp8_mj_a: 

0x5 6; 

// 

01010110 


cp8 

(%J) , %A 

map 

cp8_mj_b: 

0x57; 

// 

01010111 

= 

cp8 

(%J) , %B 

// 




010110.. 


cp8 

%, (%) 

map 

cp8_a_mi: 

0x58; 

// 

01011000 

= 

cp8 

%A, (%I) 

map 

cp8_a_mj: 

0x5 9; 

// 

01011001 

= 

cp8 

%A, (%J) 

map 

cp8_b_mi: 

0x5A; 

// 

01011010 

= 

cp8 

%B, (%I) 

map 

cp8_b_mj: 

0x5B; 

// 

01011011 

= 

cp8 

%B, (%J) 

// 




0101110. 

= 

cp8 

#, (%) 

map 

cp8_num_mi 

.: 0 x 5 C; 

// 

01011100 

= 

cp8 

#, (%D 

map 

cp8_num_mj 

: 0x5D; 

// 

01011101 


cp8 

#, (%J) 

// 




0101111. 

= 

cp8 

(%) 

map 

cp8_mi_mj: 

0x5E; 

// 

01011110 


cp8 

(%I) 

map 

cp8_mj_mi: 

0x5F; 

// 

01011111 

= 

cp8 

(%J) 

// 














Version "D" 


857 


operands { 






#1 

r %2 = { 

+0=0x50; 

+0[1:0]=%2; +1=#1[7:0]; 

}; 

(% 

1),%2 = { 

+0=0x54; 

+ 0[1:1]=%1; +0 [0:1 

0]=%2; 

}; 

%1 

, (%2) = { 

+0=0x58; 

+ 0[1:1]=%1; +0 [0:1 

0]=%2; 

}; 

#1 

, (%2) = { 

+0=0x5C; 

+0[0:0]=%2; +1=#1[7:0]; 

}; 

(% 

1) = { 

+0=0x5E; 

+0[0:0]=%1; }; 



}; 

}; 







// 







op push { 






// 




01100... = push 

% 


map 

push_i: 

0x60; 

// 

01100000 = push 

%I 


map 

push_j: 

0x61; 

// 

01100001 = push 

%J 


map 

push_a: 

0x62; 

// 

01100010 = push 

%A 


map 

push_b: 

0x63; 

// 

01100011 = push 

%B 


map 

push_bp: 

0x64; 

// 

01100100 = push 

%BP 


map 

push_sp: 

0x65; 

// 

01100101 = push 

%SP 


map 

push_c: 

0x66; 

// 

01100110 = push 

%c 


map 

push_f1: 

0x67; 

// 

01100111 = push 

%FL 


// 







map 

push_num: 

0x80; 

// 

10000000 = push 

# 


// 







map 

push_mi: 

0x82; 

// 

10000010 = push 

(%I) 


map 

push_mj: 

0x83; 

// 

10000011 = push 

(%J) 


// 







operands { 






%1 

= { +o= 

0x60; +0[2:0 

]=%i; }; 



#1 

= { +o= 

0x80; +1= 

=#1 [7:0] ; +2=#1 [15:1 

3]; }; 


(% 

1) = { +0= 

0x82; +0[0:0 

]=%i; }; 



}; 







}; 







op pop { 






// 




OHIO. . . = pop 

% 


map 

pop_i: 

0x7 0; 

// 

01110000 = pop 

%I 


map 

pop_j: 

0x71; 

// 

01110001 = pop 

%J 


map 

pop_a: 

0x72; 

// 

01110010 = pop 

%A 






858 


Version "D" 


map 

pop_b: 0x73; 

// 

01110011 


pop %B 

map 

pop_bp: 0x74; 

// 

01110100 

= 

pop %BP 

map 

pop_sp: 0x75; 

// 

01110101 

= 

pop %SP 

map 

pop_c: 0x76; 

// 

01110110 

= 

pop %C 

map 

pop_fl: 0x77; 

// 

01110111 

= 

pop %FL 

// 



1000011. 

= 

pop (%) 

map 

pop_mi: 0x86; 

// 

10000110 

= 

pop (%I) 

map 

pop_mj: 0x87; 

// 

10000111 


pop (%J) 

// 







operands { 






o 

"o 

1 = { +0 = 0x70; +0 [2:0 

]=%1; }; 




( 

\. 

%1) = { +0 = 0x86; +0 [0:0 

]=%i; }; 




S' 

}; 







// 







op push8 { 






// 



01101... 

= 

push 8 

% 

map 

push8_i: 0x68; 

// 

01101000 

= 

push 8 

%I 

map 

push8_j: 0x69; 

// 

01101001 

= 

push 8 

%J 

map 

push8_a: 0x6A; 

// 

01101010 

= 

push 8 

%A 

map 

push8_b: 0x6B; 

// 

01101011 


push 8 

%B 

map 

push8_bp: 0x6C; 

// 

01101100 

= 

push 8 

%BP 

map 

push8_sp: 0x6D; 

// 

01101101 


push 8 

%SP 

map 

push8_c: 0x6E; 

// 

01101110 

= 

push 8 

%C 

map 

push8_fl: 0x6F; 

// 

01101111 

= 

push 8 

%FL 

// 







map 

push8_num: 0x81; 

// 

10000001 

= 

push 8 

# 

// 



1000010. 

= 

push 8 

(%I) 

map 

push8_mi: 0x84; 

// 

10000100 

= 

push 8 

(%I) 

map 

push8_mj: 0x85; 

// 

10000101 

= 

push 8 

(%J) 

// 







operands { 






o 

"o 

1 = { +0 = 0x68; +0 [2:0 

]=%1; }; 




#1 = { +0 = 0x81; +1 [7:0 

]=#i; }; 




( 

}; 

%1) = { +0=0x81; +0 [0:0 

]=%i; }; 







Version "D" 


859 


}; 

op pop8 { 









// 




01111. . . 

= 

pop 8 

% 



map 

pop8_i: 

0x7 8; 

// 

01111000 

= 

pop 8 

%I 



map 

pop8_j: 

0x7 9; 

// 

01111001 

= 

pop 8 

%J 



map 

pop8_a: 

0x7A; 

// 

01111010 

= 

pop 8 

%A 



map 

pop8_b: 

0 x 7 B; 

// 

01111011 

= 

pop 8 

%B 



map 

pop8_bp: 

0x7C; 

// 

01111100 


pop 8 

%BP 



map 

pop8_sp: 

0x7D; 

// 

01111101 

= 

pop 8 

%SP 



map 

pop8_c: 

0x7E; 

// 

01111110 

= 

pop 8 

%C 



map 

pop8_f1: 

0x7F; 

// 

01111111 

= 

pop 8 

%FL 



// 



// 

1000100. 


pop 8 

(%) 



map 

pop8_mi: 

0x88; 

// 

10001000 

= 

pop 8 

(%I) 



map 

pop8_mj: 

0x89; 

// 

10001001 

= 

pop 8 

(%J) 



// 










operands { 









o 

o 

1 = { +0= 

0x78; +0 [2:0 

]=%i; }; 






< 

}; 

%1) = { +0= 

0x88; +0 [0:0 

] =%i; }; 






}; 

// 










op jump { 









map 

jump_nc: 

0x90; 

// 

10010000 


jimp 

%carry 

0 # 


map 

j ump_c: 

0x91; 

// 

10010001 

= 

jump 

%carry 

1 # 


map 

jump_nz: 

0x92; 

// 

10010010 


jump 

%zero 

0 # 


map 

jump_z: 

0x93; 

// 

10010011 

= 

jump 

%zero 

1 # 


map 

jump_nn: 

0x94; 

// 

10010100 

= 

jump 

%negative 0 

# 

map 

j ump_n : 

0x95; 

// 

10010101 

= 

jump 

%negative 1 

# 

map 

jump_no: 

0x96; 

// 

10010110 

= 

jump 

%overflow 0 

# 

map 

j ump_o: 

0x97; 

// 

10010111 

= 

jump 

%overflow 1 

# 

// 










map 

jump: 

OxFE; 

// 

11111110 

= 

jump 

# 



// 










operands { 










%1,#2,#3 = 

{ +0=0x90 

; +0[2:1]=%1 

} 

+ 0 [0 : 

0 ] = # 2 ; 





+ 1=#3 [ 7 

: 0 ] 

; +2=#3 [ 15 : 

:8]; } 









860 


Version "D" 


#1 

}; 

}; 

// 

op equal { 
map equal: 
operands { 

}; 

op not { 
map not: 
operands { 

}; 

// 

op and { 
map and: 
operands { 

}; 

op nand { 
map nand: 
operands { 

}; 

// 

op or { 
map or: 
operands { 

}; 

op nor { 
map nor: 
operands { 

}; 

// 

op xor { 
map xor: 
operands { 

}; 

op nxor { 


= { +0=0xFE; +1=#1[7:0] ; +2=#1[15:8]; }; 


0x98; // 10011000 = equal 

- = { +0=0x98; }; }; 


0x99; // 10011001 = not 

- = { +0=0x99; }; }; 


0x9A; // 10011010 = and 

- = { +0=0x9A; }; }; 


0x9B; // 10011011 = nand 

- = { +0=0x9B; }; }; 


0x9C; // 10011100 = or 

- = { +0=0x9C; }; }; 


0x9D; // 10011101 = nor 

- = { +0=0x9D; }; }; 


0x9E; // 10011110 = xor 

- = { +0=0x9E; }; }; 



Version "D" 


861 


map nxor: 
operands { 

}; 

// 

op add { 
map add: 
operands { 

}; 

op sub { 
map sub: 
operands { 

}; 

// 

op addc { 
map addc: 
operands { 

}; 

op subb { 
map subb: 
operands { 

}; 

// 

op lshl { 
map lshl: 
operands { 

}; 

op lshr { 
map lshr: 
operands { 

}; 

// 

op ashl { 
map ashl: 
operands { 

}; 

op ashr { 


0x9F; // 10011111 = nxor 

{ +0=0x9F; }; }; 


OxAO; // 10100000 = add 

{ +0=0xA0; }; }; 


OxAl; // 10100001 = sub 

{ +0=0xAl; }; }; 


0xA2; // 10100010 = addc 

{ +0=0xA2; }; }; 


0xA3; // 10100011 = subb 

{ +0=0xA3; }; }; 


0xA4; // 10100100 = lshl 

{ +0=0xA4; }; }; 


0xA5; // 10100101 = lshr 

{ +0=0xA5; }; }; 


0xA6; // 10100110 = ashl 

{ +0=0xA6; }; }; 



862 


Version "D" 


map ashr: 
operands { 

}; 

// 

op rotcl { 
map rotcl: 
operands { 

}; 

op rotcr { 
map rotcr: 
operands { 

}; 

// 

op rotl { 
map rotl: 
operands { 

}; 

op rotr { 
map rotr: 
operands { 

}; 

// 

op add8 { 
map add8: 
operands { 

}; 

op sub8 { 
map sub8: 
operands { 

}; 

// 

op add8c { 
map add8c: 
operands { 

}; 

op sub8b { 


0xA7; // 10100111 = ashr 

{ +0=0xA7; }; }; 


0xA8; // 10101000 = rotcl 

{ +0=0xA8; }; }; 


0xA9; // 10101001 = rotcr 

{ +0=0xA9; }; }; 


OxAA; // 10101010 = rotl 

{ +0=0xAA; }; }; 

OxAB; // 10101011 = rotr 

{ +0=0xAB; }; }; 


0 xAC; // 10101100 = add8 

{ +0 = 0 xAC; }; }; 


OxAD; // 10101101 = sub8 

{ +0=0xAD; }; }; 


OxAE; // 10101110 = addc8 

{ +0=0xAE; }; }; 



Version "D" 


863 


map sub8b: 
operands { - 

}; 

// 

op lsh81 { 
map lsh81: 
operands { - 

}; 

op lsh8r { 
map lsh8r: 
operands { - 

}; 

// 

op ash81 { 
map ash81: 
operands { - 

}; 

op ash8r { 
map ash8r: 
operands { - 

}; 

// 

op rot8cl { 
map rot8cl: 
operands { - 

}; 

op rot8cr { 
map rot8cr: 
operands { - 

}; 

// 

op rot81 { 
map rot81: 
operands { - 

}; 

op rot8r { 


0 xAF; // 10101111 

{ +0=0xAF; }; }; 


OxBO; // 10110000 

{ +0=0xB0; }; }; 


OxBl; // 10110001 

{ +0=0xBl; }; }; 


0xB2; // 10110010 

{ +0=0xB2; }; }; 


0xB3; // 10110011 

{ +0=0xB3; }; }; 


0xB4; // 10110100 

{ +0=0xB4; }; }; 


0xB5; // 10110101 

{ +0=0xB5; }; }; 


0xB6; // 10110110 

{ +0=0xB6; }; }; 


subb8 


lsh!81 


lsh!8r 


ash!81 


ashl8r 


rotc81 


rotc8r 


rot 81 



864 


Version "D" 


map rot8r: 0xB7; // 10110111 = rot8r 

operands { - = { +0=0xB7; }; }; 

}; 

// 


op cast { 


// 


// 

101110.. = cast 

<sig>, % 

map cast_uns_a: 

0xB8; 

// 

10111000 = cast 

0, %A 

map cast_uns_b: 

0xB9; 

// 

10111001 = cast 

0, %B 

map cast_sig_a: 

OxBA; 

// 

10111010 = cast 

1, %A 

map cast_sig_b: 
operands { 

OxBB; 

// 

10111011 = cast 

1, %B 


#1,%2 = {+0=0xB8; +0[1:1]=#1; +0[0:0]=%2; }; 

}; 

}-• 

// 


op equals { 
map equals: 
operands { - 

}; 

op nots { 
map nots: 
operands { - 

}; 

// 

op ands { 
map ands: 
operands { - 

}; 

op nands { 
map nands: 
operands { - 

}; 

// 

op ors { 
map ors: 
operands { - 


OxBC; // 10111100 = stack <= %A 

{ +0=0xBC; }; }; 


OxBD; // 10111101 = stack <= NOT %A 

{ +0=0xBD; }; }; 


OxBE; // 10111110 = stack <= %A AND %B 

{ +0=0xBE; }; }; 


OxBF; // 10111111 = stack <= %A NAND %B 

{ +0=0xBF; }; }; 


OxCO; // 11000000 = stack <= %A OR %B 

{ +0=0xC0; }; }; 




Version "D" 


865 


}; 

op nors { 
map nors: 
operands { 

}; 

// 

op xors { 
map xors: 
operands { 

}; 

op nxors { 
map nxors: 
operands { 

}-• 

// 

op adds { 
map adds: 
operands { 

}; 

op subs { 
map subs: 
operands { 

}; 

// 

op addcs { 
map addcs: 
operands { 

}; 

op subbs { 
map subbs: 
operands { 

}; 

// 

op lshls { 
map lshls: 
operands { 


OxCl; // 11000001 = stack <= %A NOR %B 

{ +0=0xCl; }; }; 


0xC2; // 11000010 = stack <= %A XOR %B 

{ +0=0xC2; }; }; 


0xC3; // 11000011 = stack <= %A NXOR %B 

{ +0=0xC3; }; }; 


0xC4; // 11000100 = stack <= %A + %B 

{ +0=0xC4; }; }; 


0xC5; // 11000101 = stack <= %A - %B 

{ +0=0xC5; }; }; 


0xC6; // 11000110 = stack <= %A + %B + %carry 

{ +0=0xC6; }; }; 


0xC7; // 11000111 = stack <= %A — %B — %carry 

{ +0=0xC7; }; }; 


0xC8; // 11001000 = stack <= lshl 

{ +0=0xC8; }; }; 



866 


Version "D" 


}; 

op lshrs { 
map lshrs: 
operands { - 

}; 

// 

op ashls { 
map ashls: 
operands { - 

}; 

op ashrs { 
map ashrs: 
operands { - 

}-• 

// 

op rotcls { 
map rotcls: 
operands { - 

}; 

op rotcrs { 
map rotcrs: 
operands { - 

}; 

// 

op rotls { 
map rotls: 
operands { - 

}; 

op rotrs { 
map rotrs: 
operands { - 

}; 

// 

op add8s { 
map add8s: 
operands { - 


0xC9; // 11001001 = stack <= lshr 

{ +0=0xC9; }; }; 


OxCA; // 11001010 = stack <= ashl 

{ +0=0xCA; }; }; 


OxCB; // 11001011 = stack <= ashr 

{ +0=0xCB; }; }; 


OxCC; // 11001100 = stack <= rotcl 

{ +0=0xCC; }; }; 


OxCD; // 11001101 = stack <= rotcr 

{ +0=0xCD; }; }; 


OxCE; // 11001110 = stack <= rotl 

{ +0=0xCE; }; }; 


OxCF; // 11001111 = stack <= rotr 

{ +0=0xCF; }; }; 


OxDO; // 11010000 = stack8 <= + 

{ +0=0xD0; }; }; 



Version "D" 


867 


}; 

op sub8s { 
map sub8s: 
operands { - 

}; 

// 

op add8cs { 
map add8cs: 
operands { - 

}; 

op sub8bs { 
map sub8bs: 
operands { - 

}-• 

// 

op lsh81s { 
map lsh81s: 
operands { - 

}; 

op lsh8rs { 
map lsh8rs: 
operands { - 

}; 

// 

op ash81s { 
map ash81s: 
operands { - 

}; 

op ash8rs { 
map ash8rs: 
operands { - 

}; 

// 

op rot8cls { 
map rot8cls: 
operands { - 


OxDl; // 11010001 = stack8 <= - 

{ +0=0xDl; }; }; 


0xD2; // 11010010 = stack8 <= + + %carry 

{ +0=0xD2; }; }; 


0xD3; // 11010011 = stack8 <= - - %carry 

{ +0=0xD3; }; }; 


0xD4; // 11010100 = stack8 <= lsh8r 

{ +0=0xD4; }; }; 


0xD5; // 11010101 = stack8 <= lsh8r 

{ +0=0xD5; }; }; 


0xD6; // 11010110 = stack8 <= ash81 

{ +0=0xD6; }; }; 


0xD7; // 11010111 = stack8 <= ash8r 

{ +0=0xD7; }; }; 


0xD8; // 11011000 = stack8 <= rot8cl 

{ +0=0xD8; }; }; 



868 


Version "D" 


}; 

op rot8crs { 

map rot8crs: 0xD9; // 11011001 

operands { - = { +0=0xD9; }; }; 

}; 

// 

op rot81s { 

map rot81s: OxDA; // 11011010 

operands { - = { +0=0xDA; }; }; 

}; 

op rot8rs { 

map rot8rs: OxDB; // 11011011 

operands { - = { +0=0xDB; }; }; 

}; 

// 


op casts { 


// 


// 

1101110. 

map casts_uns: 

OxDC; 

// 

11011100 

map casts_sig: 
operands { 

OxDD; 

// 

11011101 


#1 = {+0=0xDC; +0[0:0]=#1; }; 

}; 

}; 

// 

op call { 

map call: OxDE; // 11011110 

map call_i: OxFC; // 11111100 

map call_j : OxFD; // 11111101 

operands { 

#1 = { +0=0xDE; +1=#1[7:0]; +2= 

(%1) = { +0=0xFC; +0[0:0]=%1; }; 

}; 

}; 

op return { 

map return: OxDF; // 11011111 

operands { - = { +0=0xDF; }; }; 


= stack8 <= rot8cr 


= stack8 <= rot81 


= stack8 <= rot8r 


= casts <sig> 
= casts 0 
= casts 1 


= call # 

= call (%I) 
= call (%J) 

#1 [ 15 : 8 ]; }; 


= return 



Version "D" 


869 


}; 

// 


op int { 

map int: OxEO; // 11100000 = int <n> 

operands { 

#1 = { +0=0xE0; +1=#1; }; 

}; 

}; 

op iret { 

map iret: OxEl; // 11100001 = iret 

operands { - = { +0=0xEl; }; }; 

}; 

// 


op imrl { 
map imrl: 
operands { 
#1 = { 

}; 

operands { 

}; 

op ivtl { 
map ivtl: 
operands { 
#1 = { 

}; 

}; 

// 


0xE2; // 11100010 = IMR load 

+0=0xE2; +1=#1[7:0]; }; 

- = { +0=0xE2; }; }; 

0xE3; // 11100011 = IVT load 

+ 0=0xE3; +1=#1 [7:0]; +2=#1[15:8]; }; 


op flag_i { 

map flag_i_clr: 0xE4; // 11100100 = flag_i 0 
map flag_i_set: 0xE5; // 11100101 = flag_i 1 

operands { 

#1 = { +0=0xE4; +0[0:0]=#1; }; 

}; 

}; 


// 


op flag_c { 



870 


Version "D" 


map flag_c_clr 

: 0xE6; 

// 11100110 

= flag_c 0 



map flag_c_set 
operands { 

: 0xE7; 

// 11100111 

= flagc 1 



#1 = { +0=0xE6; +0[0 

}; 

:0]=#1; }; 




}; 

// 






op in { 






map in_num_a: 

0xE8; 

// 11101000 

= in <n>, %A 



map in_num_b: 

0xE9; 

// 11101001 

= in <n>, %B 



map in_num_mi: 

OxEA; 

// 11101010 

= in <n>, (%I) 



map in_num_mj: 

OxEB; 

// 11101011 

= in <n>, (%J) 



operands { 






#1,%2 = { 

+0=0xE8; 

+0[0:0]=%2; 

+1=#1; }; 



#1, <%2) = { 

}; 

+0=0xEA; 

+0[0:0]=%2; 

+1=#1; }; 



}; 

op out { 






map out_a_num: 

OxEC; 

// 11101100 

= out %A, # 



map out_b_num: 

OxED; 

// 11101101 

= out %B, # 



map out_mi_num 

: OxEE; 

// 11101110 

= out (%I) ,# 



map out_mi_num 
operands { 

: OxEF; 

// 11101111 

= out (%J) , # 



%1,#2 = { 

+0=0xEC; 

+0[0:0]=%1; 

+1=#2; }; 



(%1), #2 = { 

}; 

+0=0xEE; 

+0[0:0]=%1; 

+1=#2; }; 



}; 

// 






op ifack_jump { 






map ifack_jump 
operands { 

: OxFO; 

// 11110000 

= jump if ack 

from 

device 

#1,#2 = { 

}; 

+0=0xF0; 

+1=#1; +2=#2[7:0]; +3=#2[15:8]; 

}; 

}; 

op ifack_call { 






map ifack_call 

: OxFl; 

// 11110001 

= call if ack 

from 

device 



Version "D" 


871 


operands { 

# 1,#2 

}; 

}; 

// 

op cmpr { 
map cmpr: 
operands { 

}; 

op testr { 
map testr: 
operands { 

}; 

// 

op cmpi { 
map cmpi: 
operands { 

}; 

op testi { 
map testi: 
operands { 

}; 

// 

op cmps { 
map cmps: 
operands { 

}; 

op tests { 
map tests: 
operands { 

}; 

// 

op cmp 8i { 
map cmp8i: 
operands { 

I; 


{ +0=0xFl; +1=#1; +2=#2[7:0]; +3=#2[15:8]; }; 


0xF2; // 11110010 = compare %A, %B 

= { +0[7:0]=0xF2; }; }; 


0xF3; // 11110011 = test %A, %B 

= { +0[7:0]=0xF3; }; }; 


0xF4; // 11110100 = compare (%I), (%J) 

= { +0[7:0]=0xF 4; }; }; 


0xF5; // 11110101 = test (%I ), (%J) 

= { +0[7:0]=0xF5; }; }; 


0xF6; // 11110110 = compare stack 

= { +0[7:0]=0xF6; }; }; 


0xF7; // 11110111 = test stack 

= { +0[7:0]=0xF7; }; }; 


0xF8; // 11111000 = compare8 (%I), (%J) 

= { +0[7:0]=0xF8; }; }; 



872 


Version "D" 


op test8i { 


map test8i: 

OxF9; // 11111001 = tests (%I), (%J) 

operands { - 

= { +0[7:0]=0xF9; }; }; 

}; 


// 


op cmp 8 s { 


map cmp8s: 

OxFA; // 11111010 = compare8 stack 

operands { - 

= { +0[7:0]=0xFA; }; }; 

}; 


op test8s { 


map test8s: 

OxFB; // 11111011 = test8 stack 

operands { - 

= { +0[7:0]=0xFB; }; }; 

}; 


// 


op stop { 


map stop: 

OxFF; // 11111111 

operands { - 

= { +0[7:0]=0xFF; }; }; 

}; ' 



12.15 Microcode 

It follows the microcode listing, describing the opcode procedures. 
Listing 12.43. Microcode for TKGate. 

begin microcode @ 0 

// 

fetch: 

// IR[7:0] <= RAM[PC++], MPC <= IR[7:0] 

ir=select_bus_b ir=rank_8 ir=register_load_byte_l ir=select_byte_l 
ram= s e1e ct_bu s_b ram=bus_writ e ram=p 
pc=dpl ctrl=load; 

// 

nop: 

// MPC <= #fetch 

addr=fetch jump=true; 

// 

cp_i_j: 




Version "D" 


873 


// J <= I, MPC <= §fetch 

j=select_bus_a j=rank_l6 j=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 


cp_i_a: 

// A <= I , MPC <= #fetch 

a=select_bus_a a=rank_l6 a=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 


cp_i_b: 

// B <= I, MPC <= #fetch 

b=select_bus_a b=rank_l6 b=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 
cp_i_sp: 


// SP <= I, MPC <= #fetch 

sp=select_bus_a sp=rank_l6 sp=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 
cp_i_bp: 

// BP <= I , MPC <= #fetch 

bp=select_bus_a bp=rank_l6 bp=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 


cp_i_c: 

// C <= I, MPC <= #fetch 

c=select_bus_a c=rank_l6 c=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 
cp_i_f1: 

// FL <= I, MPC <= #fetch 

fl=select_bus_a fl=rank_l6 fl=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 


cp_ j_i : 

// I <= JMPC <= #fetch 

i=select_bus_a i=rank_l6 i=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 


cp_j_a: 

// A <= J , MPC <= #fetch 



874 


Version "D" 


a=select_bus_a a=rank_l6 a=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 
cp_j_b: 

// B <= J, MFC <= #fetch 

b=select_bus_a b=rank_l6 b=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 
cp_j_sp: 

// SP <= J, MFC <= #fetch 

sp=select_bus_a sp=rank_l6 sp=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 
cp_j_bp: 

// BP <= J, MPC <= #fetch 

bp=select_bus_a bp=rank_l6 bp=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 
cp_ j_c: 

// C <= J, MPC <= # fetch 

c=select_bus_a c=rank_l6 c=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 

cp_j_fl: 

// FL <= J, MPC <= #fetch 

fl=select_bus_a fl=rank_l6 fl=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 
cp_a_i : 

// J <= A, MPC <= #fetch 

i=select_bus_a i=rank_l6 i=register_load 
a=select_bus_a a=rank_l6 a=bus_write 
addr=fetch jump=true; 
cp_a_ j : 

// J <= A , MPC <= #fetch 

j=select_bus_a j=rank_l6 j=register_load 
a=select_bus_a a=rank_l6 a=bus_write 
addr=fetch jump=true; 
cp_a_b: 

// B <= A, MPC <= #fetch 

b=select_bus_a b=rank_l6 b=register_load 



Version "D" 


875 


a=select_bus_a a=rank_l6 a=bus_write 
addr=fetch jump=true; 
cp_a_sp: 

// SP <= A, MFC <= #fetch 

sp=select_bus_a sp=rank_l6 sp=register_load 
a=select_bus_a a=rank_l6 a=bus_write 
addr=fetch jump=true; 
cp_a_bp: 

// BP <= A, MPC <= #fetch 

bp=select_bus_a bp=rank_l6 bp=register_load 
a=select_bus_a a=rank_l6 a=bus_write 
addr=fetch jump=true; 


// C <= A, MPC <= #fetch 

c=select_bus_a c=rank_l6 c=register_load 
a=select_bus_a a=rank_l6 a=bus_write 
addr=fetch jump=true; 


cp_a_f1: 

// FL <= A, MPC <= #fetch 

fl=select_bus_a fl=rank_l6 fl=register_load 
a=select_bus_a a=rank_l6 a=bus_write 
addr=fetch jump=true; 
cp_b_i : 

// I <= B, MPC <= #fetch 

i=select_bus_a i=rank_l6 i=register_load 
b=select_bus_a b=rank_l6 b=bus_write 
addr=fetch jump=true; 


cp_b_ j : 

// J <= B, MPC <= #fetch 

j=select_bus_a j=rank_l6 j=register_load 
b=select_bus_a b=rank_l6 b=bus_write 
addr=fetch jump=true; 


cp_b_a: 

// A <= B, MPC <= #fetch 

a=select_bus_a a=rank_l6 a=register_load 
b=select_bus_a b=rank_l6 b=bus_write 
addr=fetch jump=true; 
cp_b_sp: 

// SP <= B, MPC <= #fetch 

sp=select_bus_a sp=rank_l6 sp=register_load 
b=select_bus_a b=rank_l6 b=bus_write 



876 


Version "D" 


addr=fetch jump=true; 
cp_b_bp: 

// BP <= B, MPC <= #fetch 

bp=select_bus_a bp=rank_l6 bp=register_load 
b=select_bus_a b=rank_l6 b=bus_write 
addr=fetch jump=true; 
cp_b_c: 

// C <= B, MPC <= #fetch 

c=select_bus_a c=rank_l6 c=register_load 
b=select_bus_a b=rank_l6 b=bus_write 
addr=fetch jump=true; 
cp_b_f1: 

// FL <= B, MPC <= #fetch 

fl=select_bus_a fl=rank_l6 fl=register_load 
b=select_bus_a b=rank_l6 b=bus_write 
addr=fetch jump=true; 
cp_sp_i : 

// I <= SP, MPC <= #fetch 

i=select_bus_a i=rank_l6 i=register_load 
sp=select_bus_a sp=rank_l6 sp=bus_write 
addr=fetch jump=true; 
cp_sp_j : 

// J <= SP, MPC <= #fetch 

j=select_bus_a j=rank_l6 j=register_load 
sp=select_bus_a sp=rank_l6 sp=bus_write 
addr=fetch jump=true; 
cp_sp_a: 

// A <= SP, MPC <= #fetch 

a=select_bus_a a=rank_l6 a=register_load 
sp=select_bus_a sp=rank_l6 sp=bus_write 
addr=fetch jump=true; 
cp_sp_b: 

// B <= SP, MPC <= #fetch 

b=select_bus_a b=rank_l6 b=register_load 
sp=select_bus_a sp=rank_l6 sp=bus_write 
addr=fetch jump=true; 
cp_sp_bp: 

// BP <= SP , MPC <= #fetch 

bp=select_bus_a bp=rank_l6 bp=register_load 
sp=select_bus_a sp=rank_l6 sp=bus_write 
addr=fetch jump=true; 



Version "D" 


877 


cp_sp_c: 

// C <= SP, MFC <= #fetch 

c=select_bus_a c=rank_l6 c=register_load 
sp=select_bus_a sp=rank_l6 sp=bus_write 
addr=fetch jump=true; 
cp_sp_f1: 

// FL <= SP, MPC <= #fetch 

fl=select_bus_a fl=rank_l6 fl=register_load 
sp=select_bus_a sp=rank_l6 sp=bus_write 
addr=fetch jump=true; 
cp_bp_i: 

// I <= BP, MPC <= #fetch 

i=select_bus_a i=rank_l6 i=register_load 
bp=select_bus_a bp=rank_l6 bp=bus_write 
addr=fetch jump=true; 
cp_bp_j: 

// J <= BP , MPC <= #fetch 

j=select_bus_a j=rank_l6 j=register_load 
bp=select_bus_a bp=rank_l6 bp=bus_write 
addr=fetch jump=true; 
cp_bp_a: 

// A <= BP, MPC <= #fetch 

a=select_bus_a a=rank_l6 a=register_load 
bp=select_bus_a bp=rank_l6 bp=bus_write 
addr=fetch jump=true; 
cp_bp_b: 

// B <= BP , MPC <= #fetch 

b=select_bus_a b=rank_l6 b=register_load 
bp=select_bus_a bp=rank_l6 bp=bus_write 
addr=fetch jump=true; 
cp_bp_sp: 

// SP <= BP , MPC <= #fetch 

sp=select_bus_a sp=rank_l6 sp=register_load 
bp=select_bus_a bp=rank_l6 bp=bus_write 
addr=fetch jump=true; 
cp_bp_c: 

// C <= BP, MPC <= #fetch 

c=select_bus_a c=rank_l6 c=register_load 
bp=select_bus_a bp=rank_l6 bp=bus_write 
addr=fetch jump=true; 
cp_bp_f 1: 



878 


Version "D" 


// FL <= BP, MFC <= #fetch 

fl=select_bus_a fl=rank_l6 fl=register_load 
bp=select_bus_a bp=rank_l6 bp=bus_write 
addr=fetch jump=true; 
cp_c_i : 

// I <= C, MPC <= #fetch 

i=select_bus_a i=rank_l6 i=register_load 
c=select_bus_a c=rank_l6 c=bus_write 
addr=fetch jump=true; 
cp_c_ j : 

// J <= C, MPC <= #fetch 

j=select_bus_a j=rank_l6 j=register_load 
c=select_bus_a c=rank_l6 c=bus_write 
addr=fetch jump=true; 


cp_c_a: 

// A <= C, MPC <= #fetch 

a=select_bus_a a=rank_l6 a=register_load 
c=select_bus_a c=rank_l6 c=bus_write 
addr=fetch jump=true; 
cp_c_b: 

// B <= C, MPC <= #fetch 

b=select_bus_a b=rank_l6 b=register_load 
c=select_bus_a c=rank_l6 c=bus_write 
addr=fetch jump=true; 
cp_c_sp: 

// SP <= C, MPC <= #fetch 

sp=select_bus_a sp=rank_l6 sp=register_load 
c=select_bus_a c=rank_l6 c=bus_write 
addr=fetch jump=true; 
cp_c_bp: 

// BP <= C, MPC <= #fetch 

bp=select_bus_a bp=rank_l6 bp=register_load 
c=select_bus_a c=rank_l6 c=bus_write 
addr=fetch jump=true; 
cp_c_f1: 

// FL <= C, MPC <= #fetch 

fl=select_bus_a fl=rank_l6 fl=register_load 
c=select_bus_a c=rank_l6 c=bus_write 
addr=fetch jump=true; 
cp_fl_i : 

// J <= FL, MPC <= #fetch 



Version "D" 


879 


i=select_bus_a i=rank_l6 i=register_load 
fl=select_bus_a fl=rank_l6 fl=bus_write 
addr=fetch jump=true; 
cp_fl_j: 

// J <= FL, MFC <= #fetch 

j=select_bus_a j=rank_l6 j=register_load 
fl=select_bus_a fl=rank_l6 fl=bus_write 
addr=fetch jump=true; 


cp_fl_a: 

// A <= FL, MFC <= #fetch 

a=select_bus_a a=rank_l6 a=register_load 
fl=select_bus_a fl=rank_l6 fl=bus_write 
addr=fetch jump=true; 


cp_f l_b: 

// B <= FL, MFC <= #fetch 

b=select_bus_a b=rank_l6 b=register_load 
fl=select_bus_a fl=rank_l6 fl=bus_write 
addr=fetch jump=true; 
cp_fl_sp: 

// SP <= FL, MPC <= #fetch 

sp=select_bus_a sp=rank_l6 sp=register_load 
fl=select_bus_a fl=rank_l6 fl=bus_write 
addr=fetch jump=true; 
cp_f l_bp: 

// BP <= FL, MPC <= #fetch 

bp=select_bus_a bp=rank_l6 bp=register_load 
fl=select_bus_a fl=rank_l6 fl=bus_write 
addr=fetch jump=true; 


cp_fl_c: 

// C <= FL, MPC <= #fetch 

c=select_bus_a c=rank_l6 c=register_load 
fl=select_bus_a fl=rank_l6 fl=bus_write 
addr=fetch jump=true; 
cp_num_i: 


// I[7:0] <= RAM[PC++] 


i=select_bus_a i=rank_8 i=register_load_byte_l i=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// I [15: 8] <= RAM[PC++], MPC <= #fetch 

i=select_bus_a i=rank_8 i=register_load_byte_2 i=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 



880 


Version "D" 


cp_num_j: 

// J[7: 0] <= RAM[PC++] 

j=select_bus_a j=rank_8 j=register_load_byte_l j=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// J[15:8] <= RAM[PC++], MPC <= # fetch 

j=select_bus_a j=rank_8 j=register_load_byte_2 j=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 
cp_num_a: 

// A[7: 0] <= RAM[PC++] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// A[15:8] <= RAM[PC++], MPC <= # fetch 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 
cp_num_b: 

// B[7: 0] <= RAM[PC++] 


b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// B [15:8] <= RAM[PC++] , MPC <= #fetch 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 
cp_mi_a: 

// A[7:0] <= RAM[I] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=i; 

// A[15:8] <= RAM[1+1 ] , MPC <= #fetch 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=i i=qpl 
addr=fetch jump=true; 
cp_mi_b: 

// B[7: 0] <= RAM[I] 


b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=i; 

// B [15:8] <= RAM[ 1+1 ] , MPC <= #fetch 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=i i=qpl 
addr=fetch jump=true; 
cp_mj_a: 



Version "D" 


881 


// A[7:0] <= RAM[J] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram= j; 

// A[15:8] <= RAM[J+l], MFC <= #fetch 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=j j=qpl 
addr=fetch jump=true; 
cp_mj_b: 

// B[7: 0] <= RAM[J] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram= j; 

// B [15:8] <= RAM [J+l], MFC <= # fetch 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=j j=qpl 
addr=fetch jump=true; 
cp_a_mi: 

// RAM[I] <= A[7:0] 


ram=select_bus_a ram=load ram=i 

a=select_bus_a a=rank_8 a=select_byte_l a=bus_write; 

// RAM[1+1] <= A[15:8 ], MFC <= #fetch 

ram=select_bus_a ram=load ram=i i=qpl 
a=select_bus_a a=rank_8 a=select_byte_2 a=bus_write 
addr=fetch jump=true; 
cp_a_mj: 

// RAM[J] <= A[7:0] 


ram=select_bus_a ram=load ram=j 

a=select_bus_a a=rank_8 a=select_byte_l a=bus_write; 

// RAM [J+l] <= A[15:8], MFC <= # fetch 

ram=select_bus_a ram=load ram=j j=qpl 
a=select_bus_a a=rank_8 a=select_byte_2 a=bus_write 
addr=fetch jump=true; 
cp_b_mi: 

// RAM[I] <= B[7: 0] 


ram=select_bus_a ram=load ram=i 

b=select_bus_a b=rank_8 b=select_byte_l b=bus_write; 

// RAM[1+1] <= B[15:8 ], MFC <= #fetch 

ram=select_bus_a ram=load ram=i i=qpl 
b=select_bus_a b=rank_8 b=select_byte_2 b=bus_write 
addr=fetch jump=true; 


cp_b_mj: 

// RAM[J] <= B[7: 0] 



882 


Version "D" 


ram=select_bus_a ram=load ram=j 

b=select_bus_a b=rank_8 b=select_byte_l b=bus_write; 

// RAM[J+l] <= B[15:8] , MFC <= #fetch 

ram=select_bus_a ram=load ram=j j=qpl 
b=select_bus_a b=rank_8 b=select_byte_2 b=bus_write 
addr=fetch jump=true; 
cp_num_mi: 

// TMP[7:0] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// TMP [15:8] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// RAM [I] <= TMP [7:0] 

ram=select_bus_a ram=load ram=i 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write; 

// RAM[1+1] <= TMP [15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=i i=qpl 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write 
addr=fetch jump=true; 
cp_num_mj: 

// TMP[7:0] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// TMP [15:8] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// RAM[J] <= TMP[7:0] 

ram=select_bus_a ram=load ram=j 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write; 

// RAM [J+l] <= TMP [15: 8], MPC <= # fetch 

ram=select_bus_a ram=load ram=j j=qpl 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write 
addr=fetch jump=true; 
cp_mi_mj: 

// TMP[7:0] <= RAM[I] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=i; 

// TMP [15:8] <= RAM[ 1+1] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=i i=qpl; 



Version "D" 


883 


// RAM[J] <= TMP[7:0] 

ram=select_bus_a ram=load ram=j 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write; 

// RAM[J+l] <= TMP[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=j j=qpl 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write 
addr=fetch jump=true; 
cp_mj_mi: 

// TMP[7:0] <= RAM[J] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram= j; 

// TMP [15:8] <= RAM [J+l] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=j j=qpl; 

// RAM [I] <= TMP [7:0] 

ram=select_bus_a ram=load ram=i 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write; 

// RAM[1+1] <= TMP[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=i i=qpl 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write 
addr=fetch jump=true; 
cp8_num_i: 

// I <= RAM[PC++], MPC <= #fetch 

i=select_bus_a i=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 
cp8_num_j: 

// J <= RAM[PC++], MPC <= #fetch 

j=select_bus_a j=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 
cp8_num_a: 

// A <= RAM[PC++], MPC <= #fetch 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 
cp8_num_b: 

// B <= RAM[PC++], MPC <= #fetch 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 



884 


Version "D" 


cp8_mi_a: 

// A <= RAM[I] , MPC <= #fetch 

a=select_bus_a a=register_load 
ram= s e1e ct_bu s_a ram=bu s_writ e 
addr=fetch jump=true; 
cp8_mi_b: 

// B <= RAM[I], MPC <= #fetch 

b=select_bus_a b=register_load 
ram= s e1e ct_bu s_a ram=bus_writ e 
addr=fetch jump=true; 
cp8_mj_a: 

// A <= RAM[J], MPC <= #fetch 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write 
addr=fetch jump=true; 
cp8_mj_b: 

// B <= RAM[J], MPC <= #fetch 

b=select_bus_a b=register_load 
ram= s e1e ct_bu s_a ram=bu s_writ e 
addr=fetch jump=true; 
cp8_a_mi: 

// RAM [I] <= B, MPC <= #fetch 

ram=select_bus_a ram=load ram=i 
a=select_bus_a a=bus_write 
addr=fetch jump=true; 
cp8_a_mj: 

// RAM[J] <= B, MPC <= #fetch 

ram=select_bus_a ram=load ram=; 
a=select_bus_a a=bus_write 
addr=fetch jump=true; 
cp8_b_mi: 

// RAM [I] <= B, MPC <= # fetch 

ram=select_bus_a ram=load ram=i 
b=select_bus_a b=bus_write 
addr=fetch jump=true; 
cp8_b_mj: 

// RAM[J] <= B, MPC <= #fetch 

ram=select_bus_a ram=load ram=; 
b=select_bus_a b=bus_write 
addr=fetch jump=true; 
cp8_num_mi: 


ram=i 


ram=i 


ram= j 


ram= j 



Version "D" 


885 


// TMP <= RAM [PC++] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// RAM [I] <= TMP , MPC <= #fetch 

ram=select_bus_a ram=load ram=i 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
cp8_num_mj: 

// TMP <= RAM[PC++] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// RAM[J] <= TMP, MPC <= #fetch 

ram=select_bus_a ram=load ram=j 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
cp8_mi_mj: 

// TMP <= RAM[I] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=i; 

// RAM[J] <= TMP, MPC <= #fetch 

ram=select_bus_a ram=load ram=j 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
cp8_mj_mi: 

// TMP <= RAM[J] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=j; 

// RAM [I] <= TMP, MPC <= #fetch 

ram=select_bus_a ram=load ram=i 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
push_i: 

// RAM[ — SP] <= I [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
i=select_bus_a i=rank_8 i=select_byte_2 i=bus_write; 

// RAM[ — SP] <= I[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
i=select_bus_a i=rank_8 i=select_byte_l i=bus_write 
addr=fetch jump=true; 
push_j: 

// RAM[ — SP] <= J[15: 8] 



886 


Version "D" 


ram=select_bus_a ram=load ram=s sp=qml sp=qup 
j=select_bus_a j=rank_8 j=select_byte_2 j=bus_write; 

// RAM[ — SP] <= J[7: 0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
j=select_bus_a j=rank_8 j=select_byte_l j=bus_write 
addr=fetch jump=true; 
push_a: 

// RAM[ — SP] <= A[15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
a=select_bus_a a=rank_8 a=select_byte_2 a=bus_write; 

// RAM[ — SP] <= A[7:0] r MPC <= ftfetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
a=select_bus_a a=rank_8 a=select_byte_l a=bus_write 
addr=fetch jump=true; 
push_b: 

// RAM[ — SP] <= B [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
b=select_bus_a b=rank_8 b=select_byte_2 b=bus_write; 

// RAM[ — SP] <= B[7:0] r MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
b=select_bus_a b=rank_8 b=select_byte_l b=bus_write 
addr=fetch jump=true; 
push_bp: 

// RAM[ — SP] <= BP [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
bp=select_bus_a bp=rank_8 bp=select_byte_2 bp=bus_write; 

// RAM[ — SP] <= BP[7:0], MPC <= ftfetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
bp=select_bus_a bp=rank_8 bp=select_byte_l bp=bus_write 
addr=fetch jump=true; 
push_sp: 

// RAM[ — SP] <= SP [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
sp=select_bus_a sp=rank_8 sp=select_byte_2 sp=bus_write; 

// RAM[ — SP] <= SP[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
sp=select_bus_a sp=rank_8 sp=select_byte_l sp=bus_write 
addr=fetch jump=true; 
push_c: 

// RAM[ — SP] <= C [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 



Version "D" 


887 


c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write; 

// RAM[ — SP] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write 
addr=fetch jump=true; 
push_f1: 

// RAM[ — SP] <= FL [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_2 fl=bus_write; 

// RAM[ — SP] <= FL[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_l fl=bus_write 
addr=fetch jump=true; 
push_num: 

// TMP[7:0] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// TMP [15: 8] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// RAM[ — SP] <= TMP [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write; 

// RAM[ — SP] <= TMP[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write 
addr=fetch jump=true; 
push_mi: 

// TMP[7:0] <= RAM[I] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=i; 

// TMP [15:8] <= RAM[ 1+1] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=i i=qpl; 

// RAM[ — SP] <= TMP [15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write; 

// RAM[ — SP] <= TMP[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write 
addr=fetch jump=true; 



888 


Version "D" 


push_mj: 

// TMP[7:0] <= RAM[J] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram= j; 

// TMP [15:8] <= RAM [J+l] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=j j=qpl; 

// RAM[ — SP] <= TMP [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write; 

// RAM[ — SP] <= TMP[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write 
addr=fetch jump=true; 
pop_i : 

// I[7:0] <= RAM[SP++] 

i=select_bus_a i=rank_8 i=register_load_byte_l i=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// I [15:8] <= RAM[SP++], MPC <= #fetch 

i=select_bus_a i=rank_8 i=register_load_byte_2 i=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_j : 

// J[7:0] <= RAM[SP++] 

j=select_bus_a j=rank_8 j=register_load_byte_l j=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// J[15:8] <= RAM[SP++], MPC <= #fetch 

j=select_bus_a j=rank_8 j=register_load_byte_2 j=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_a: 

// A[7:0] <= RAM[SP++] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// A[15:8] <= RAM[SP++] , MPC <= #fetch 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_b: 

// B[7: 0] <= RAM[SP++] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 



Version "D" 


889 


ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// B [15:8] <= RAM [SP++], MPC <= #fetch 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_bp: 

// BP[7:0] <= RAM [SP++] 

bp=select_bus_a bp=rank_8 bp=register_load_byte_l bp=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// BP[15:8] <= RAM[SP++] , MPC <= #fetch 

bp=select_bus_a bp=rank_8 bp=register_load_byte_2 bp=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_sp: 

// SP[7:0] <= RAM[SP++] 

sp=select_bus_a sp=rank_8 sp=register_load_byte_l sp=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// SP [15:8] <= RAM[SP++] r MPC <= #fetch 

sp=select_bus_a sp=rank_8 sp=register_load_byte_2 sp=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_c: 

// C[7:0] <= RAM[SP++] 

c=select_bus_a c=rank_8 c=register_load_byte_l c=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// C[15: 8] <= RAM[SP++] , MPC <= #fetch 

c=select_bus_a c=rank_8 c=register_load_byte_2 c=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_f 1: 

// FL[7:0] <= RAM[SP++] 

fl=select_bus_a fl=rank_8 fl=register_load_byte_l fl=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// FL [15:8] <= RAM[SP++], MPC <= #fetch 

fl=select_bus_a fl=rank_8 fl=register_load_byte_2 f l=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop_mi: 

// TMP[7:0] <= RAM[SP++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 



890 


Version "D" 


// TMP [15: 8] <= RAM[SP++], MPC <= #fetch 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// RAM [I] <= TMP [7:0] 

ram=select_bus_a ram=load ram=i 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write; 

// RAM[1+1] <= TMP[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=i i=qpl 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write 
addr=fetch jump=true; 
pop_m j : 

// TMP[7:0] <= RAM[SP++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// TMP[15:8] <= RAM[SP++], MPC <= #fetch 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// RAM[J] <= TMP[7:0] 

ram=select_bus_a ram=load ram=j 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_l tmp=bus_write; 

// RAM[J+l] <= TMP[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=j j=qpl 

tmp=select_bus_a tmp=rank_8 tmp=select_byte_2 tmp=bus_write 
addr=fetch jump=true; 
push8_i: 

// RAM[ — SP] <= I, MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
i=select_bus_a i=bus_write 
addr=fetch jump=true; 
push8_j: 

// RAM[ — SP] <= J, MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
j=select_bus_a j=bus_write 
addr=fetch jump=true; 
push8_a: 

// RAM[ — SP] <= A, MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
a=select_bus_a a=bus_write 
addr=fetch jump=true; 
push8_b: 

// RAM[ — SP] <= B, MPC <= #fetch 



Version "D" 


891 


ram=select_bus_a ram=load ram=s sp=qml sp=qup 
b=select_bus_a b=bus_write 
addr=fetch jump=true; 
push8_bp: 

// RAM[ — SP] <= BP , MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
bp=select_bus_a bp=bus_write 
addr=fetch jump=true; 
push8_sp: 

// RAM[ — SP] <= SP , MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
sp=select_bus_a sp=bus_write 
addr=fetch jump=true; 
push8_c: 

// RAM[ — SP] <= C, MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
push8_f1: 

// RAM[ — SP] <= FL, MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=bus_write 
addr=fetch jump=true; 
push8_num: 

// TMP <= RAM[PC++] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// RAM[ — SP] <= TMP , MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
push8_mi: 

// TMP <= RAM[I] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=i; 

// RAM[ — SP] <= TMP, MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
push8_mj: 

// TMP <= RAM[J] 



892 


Version "D" 


tmp=select_bus_a tmp=register_load 

ram=select_bus_a ram=bus_write ram= j; 

// RAM[ — SP] <= TMP, MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 

pop8_i : 

// I <= RAM[SP++] , MPC <= #fetch 

i=select_bus_a i=register_load 

ram= s e1e ct_bu s_a ram=bus_writ e ram= s 

sp=dpl 

addr=fetch jump=true; 

pop8_j: 

// J <= RAM[SP++], MPC <= #fetch 

j=select_bus_a j=register_load 

ram= s e1e ct_bu s_a ram=bu s_writ e ram= s 

sp=dpl 

addr=fetch jump=true; 

pop8_a: 

// A <= RAM[SP++], MPC <= #fetch 

a=select_bus_a a=register_load 

ram= s e1e ct_bu s_a ram=bus_writ e ram= s 

sp=dpl 

addr=fetch jump=true; 

pop8_b: 

// B <= RAM[SP++] , MPC <= #fetch 

b=select_bus_a b=register_load 

ram= s e1e ct_bu s_a ram=bus_writ e ram= s 

sp=dpl 

addr=fetch jump=true; 

pop8_bp: 

// BP <= RAM[SP ++], MPC <= #fetch 

bp=select_bus_a bp=register_load 

ram= select_bus_a ram=bus_write ram= s 

sp=dpl 

addr=fetch jump=true; 

pop8_sp: 

// SP <= RAM [SP++] , MPC <= #fetch 

sp=select_bus_a sp=register_load 

ram= sele ct_bu s_a ram=bus_writ e ram= s 

sp=dpl 

addr=fetch jump=true; 

pop8_c: 

// C <= RAM[SP++], MPC <= #fetch 

c=select_bus_a c=register_load 

ram= sele ct_bu s_a ram=bus_writ e ram= s 

sp=dpl 

addr=fetch jump=true; 




Version "D" 


893 


pop8_f1: 

// FL <= RAM[SP++] , MFC <= #fetch 

fl=select_bus_a fl=register_load 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
pop8_mi: 

// TMP <= RAM[SP++] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// RAM [I] <= TMP, MPC <= #fetch 

ram=select_bus_a ram=load ram=i 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
pop8_mj: 

// TMP <= RAM[SP++] 

tmp=select_bus_a tmp=register_load 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// RAM[J] <= TMP, MPC <= #fetch 

ram=select_bus_a ram=load ram=j 
tmp=select_bus_a tmp=bus_write 
addr=fetch jump=true; 
jump: 

// TMP [7:0] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// TMP [15: 8] <= RAM [PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// PC <= TMP, MPC <= #fetch 

pc=select_bus_a pc=rank_l6 pc=register_load 
tmp=select_bus_a tmp=rank_l6 tmp=bus_write 
addr=fetch jump=true; 
jump_nc: 

addr=jump jump=carry_f; 

// condition failed: ignore argument and jump to next instruction 

pc=qp2 pc=qup addr=fetch jump=true; 
j ump_c: 

addr=jump jump=carry_t; 

// condition failed: ignore argument and jump to next instruction 

pc=qp2 pc=qup addr=fetch jump=true; 
jump_nz: 



894 


Version "D" 


addr=j ump jump= zero_f; 

// condition failed: ignore argument 

pc=qp2 pc=qup addr=fetch jump=true; 
jump_z: 

addr=jump jump=zero_t; 

// condition failed: ignore argument 

pc=qp2 pc=qup addr=fetch jump=true; 
jump_nn: 

addr=jump jump=negative_f; 

// condition failed: ignore argument 

pc=qp2 pc=qup addr=fetch jump=true; 
j ump_n: 

addr=jump jump=negative_t; 

// condition failed: ignore argument 

pc=qp2 pc=qup addr=fetch jump=true; 
jump_no: 

addr=jump jump=overflow_f; 

// condition failed: ignore argument 

pc=qp2 pc=qup addr=fetch jump=true; 
j ump_o: 

addr=jump jump=overflow_t; 

// condition failed: ignore argument 

pc=qp2 pc=qup addr=fetch jump=true; 


and jump to next instruction 


and jump to next instruction 


and jump to next instruction 


and jump to next instruction 


and jump to next instruction 


and jump to next instruction 


// 


equal: 

// C <= A (FL updated) , MFC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_16 
addr=fetch jump=true; 


not: 


// c <= ~A (FL updated), MFC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=not alu=rank_l6 
addr=fetch jump=true; 

and: 


// C <= A&B (FL updated), MFC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 



Version "D" 


895 


b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=and alu=rank_l6 
addr=fetch jump=true; 
nand: 

// c <= ~(A&B) (FL updated), MPC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=nand alu=rank_l6 
addr=fetch jump=true; 

or: 

// C <= A/B (FL updated), MPC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=or alu=rank_l6 
addr=fetch jump=true; 

nor : 

// c <= ~(A\B) (FL updated), MPC <= ftfetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=nor alu=rank_l6 
addr=fetch jump=true; 

xor : 

// C <= A A B (FL updated) , MPC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=xor alu=rank_l6 
addr=fetch jump=true; 
nxor: 

// C <= ~ (A*B) (FL updated), MPC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 



896 


Version "D" 


c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=nxor alu=rank_l6 
addr=fetch jump=true; 

add: 

// C <= A+B (FL updated) , MPC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=add alu=rank_l6 
addr=fetch jump=true; 

sub: 

// C <= A-B (FL updated) , MPC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_l6 
addr=fetch jump=true; 
addc: 

// C <= A+B+carry (FL updated), MPC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=addc alu=rank_l6 
addr=fetch jump=true; 
subb: 

// C <= A-B-borrow (FL updated) , MPC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=subb alu=rank_l6 
addr=fetch jump=true; 
lshl: 

// C <= lshl (A) (FL updated) , MPC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 



Version "D" 


897 


alu=lshl alu=rank_l6 
addr=fetch jump=true; 
lshr: 

// C <= lshr (A) (FL updated), MFC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=lshr alu=rank_l6 
addr=fetch jump=true; 
ashl: 

// C <= ashl (A) (FL updated) , MFC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashl alu=rank_l6 
addr=fetch jump=true; 
ashr: 

// C <= ashr (A) (FL updated), MFC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashr alu=rank_l6 
addr=fetch jump=true; 
rotcl: 

// C <= rotcl (A) (FL updated) , MFC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotcl alu=rank_l6 
addr=fetch jump=true; 
rotcr: 

// C <= rotcr(A) (FL updated), MFC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotcr alu=rank_l6 
addr=fetch jump=true; 
rot 1: 

// C <= rotl (A) (FL updated) , MFC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 



898 


Version "D" 


fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotl alu=rank_l6 
addr=fetch jump=true; 
rot r: 

// C <= rotr(A) (FL updated), MFC <= # fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotr alu=rank_l6 
addr=fetch jump=true; 
add8 : 

// C <= A[7:0]+B[7:0] (FL updated), MFC <= # fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=add alu=rank_8 
addr=fetch jump=true; 
sub8 : 

// C <= A[7:0]+B[7:0] (FL updated) , MFC <= #fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_8 
addr=fetch jump=true; 
add8c: 

// C <= A[7:0]+B[7:0] (FL updated) , MFC <= # fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=addc alu=rank_8 
addr=fetch jump=true; 
sub8b: 

// C <= A[7:0]+B[7:0] (FL updated), MFC <= # fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=subb alu=rank_8 



Version "D" 


899 


addr=fetch jump=true; 
lsh81: 

// C <= A[7:0]+B[7:0] (FL updated) , MFC <= #fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=lshl alu=rank_8 
addr=fetch jump=true; 
lsh8r: 

// C <= A[7:0]+B[7:0] (FL updated) , MFC <= # fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=lshr alu=rank_8 
addr=fetch jump=true; 
ash81: 

// C <= A[7:0]+B[7:0] (FL updated) , MFC <= # fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashl alu=rank_8 
addr=fetch jump=true; 
ash8r: 

// C <= A[7:0]+B[7:0] (FL updated), MFC <= # fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashr alu=rank_8 
addr=fetch jump=true; 
rot8cl: 

// C <= A[7:0]+B[7:0] (FL updated) , MFC <= # fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotcl alu=rank_8 
addr=fetch jump=true; 
rot8cr: 

// C <= A[7:0]+B[7:0] (FL updated) , MFC <= #fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 



900 


Version "D" 


alu=rotcr alu=rank_8 
addr=fetch jump=true; 
rot81: 

// C <= A[7:0]+B[7:0] (FL updated) , MPC <= # fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rot1 alu=rank_8 
addr=fetch jump=true; 
rot8r: 

// C <= A[7:0]+B[7:0] (FL updated) , MPC <= # fetch 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotr alu=rank_8 
addr=fetch jump=true; 

cast_uns_a: 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8; 
c=select_bus_a c=bus_write 
a=select_bus_a a=register_load 
addr=fetch jump=true; 
cast_uns_b: 

b=select_bus_a b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8; 
c=select_bus_a c=bus_write 
b=select_bus_a b=register_load 
addr=fetch jump=true; 
cast_sig_a: 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load c=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8 alu=signed; 
c=select_bus_a c=bus_write c=rank_l6 
a=select_bus_a a=register_load a=rank_l6 
addr=fetch jump=true; 



Version "D" 


901 


cast_sig_b: 

b=select_bus_a b=bus_write 
c=select_bus_b c=register_load c=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8 alu=signed; 
c=select_bus_a c=bus_write c=rank_l6 
b=select_bus_a b=register_load b=rank_16 
addr=fetch jump=true; 
equals: 

// A[7: 0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= A (FL updated), MPC <= #fetch 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_16 
addr=fetch jump=true; 
not s : 

// A[7:0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= ~A (FL updated) 
a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=not alu=rank_l6; 

// RAM[SP] <= C[7:0] 
ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
ands : 



902 


Version "D" 


// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM[SP+1 ] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM [SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= A&B (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=and alu=rank_l6; 

// RAM [ SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
nands: 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM [SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A [7:0] <= RAM [SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= ~ (A&B) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
deselect bus b b=rank 16 b=bus write 



Version "D" 


903 


c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=nand alu=rank_l6; 

// RAM[SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 

ors : 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B[15:8] <= RAM [SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM[SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM[SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= A!B (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=or alu=rank_l6; 

// RAM[SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
nors : 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM [SP+1] 



904 


Version "D" 


b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM [SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= ~ (AIB) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=nor alu=rank_l6; 

// RAM [SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
xors : 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM [SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM [SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= A A B (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=xor alu=rank_l6; 

// RAM[SP=SP+2] <= C[7:0] 



Version "D" 


905 


ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
nxors: 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM [SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM[SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM[SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// c <= ~ (A*B) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=nxor alu=rank_l6; 

// RAM[SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
adds : 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM [SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM [SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 



906 


Version "D" 


ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= A+B (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=add alu=rank_l6; 

// RAM [SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
subs : 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM [SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM[SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= A-B (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_l6; 

// RAM[SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 



Version "D" 


907 


c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
addcs: 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM[SP+1 ] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM[SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// C <= A+B+carry (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=addc alu=rank_l6; 

// RAM [ SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
subbs: 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM [SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM [SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM [SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 



908 


Version "D" 


// C <= A-B-borrow (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
b=select_bus_b b=rank_l6 b=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=subb alu=rank_l6; 

// RAM [SP=SP+2] <= C[7:0] 

ram=select_bus_a ram=load ram=s sp=qp2 sp=qup 
c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
lshls: 

// A[7:0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= lshl (A) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=lshl alu=rank_l6; 

// RAM[SP] <= C[7:0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
lshrs: 

// A[7:0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= lshr(A) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 



Version "D" 


909 


c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=lshr alu=rank_l6; 

// RAM[SP] <= C[7:0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
ashls: 

// A[7:0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= ashl(A) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashl alu=rank_l6; 

// RAM[SP] <= C[7: 0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
ashrs: 

// A[7:0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= ashr(A) (FL updated) 
a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashr alu=rank_l6; 



910 


Version "D" 


// RAM[SP] <= C[7: 0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
rotcls : 

// A[7: 0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= rotcl (A) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotcl alu=rank_l6; 

// RAM[SP] <= C[7: 0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
rotcrs: 

// A[7: 0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+1] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= rotcr (A) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotcr alu=rank_l6; 

// RAM[SP] <= C[7: 0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 



Version "D" 


911 


// RAM[SP+l] <= C[15:8], MPC <= §fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
rotls: 

// A[7:0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+l] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= rotl(A) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rot1 alu=rank_l6; 

// RAM[SP] <= C[7: 0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+l] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
rotrs: 

// A[7: 0] <= RAM[SP] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// A[15:8] <= RAM [SP+l] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// C <= rotr(A) (FL updated) 

a=select_bus_a a=rank_l6 a=bus_write 
c=select_bus_b c=rank_l6 c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotr alu=rank_l6; 

// RAM[SP] <= C[7: 0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+l] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 



912 


Version "D" 


addr=fetch jump=true; 
add8s: 

// B <= RAM[SP] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// A <= RAM [SP+1] 
a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 
// C <= A+B (FL updated) 
a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=add alu=rank_8; 

// RAM[SP=SP+1 ] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl sp=qup 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
sub8s: 

// B <= RAM[SP] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// A <= RAM [SP+1] 
a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 
// C <= A-B (FL updated) 
a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_8; 

// RAM[SP=SP+1] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl sp=qup 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
add8cs: 

// B <= RAM[SP] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// A <= RAM [SP+1] 

a=select_bus_a a=register_load 



Version "D" 


913 


ram=select_bus_a ram=bus_write ram=s sp=qpl; 
// C <= A+B+carry (FL updated) 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=addc alu=rank_8; 

// RAM[SP=SP+1] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl sp=qup 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
sub8bs: 

// B <= RAM[SP] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// A <= RAM[SP+1 ] 
a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 
// C <= A-B-borrow (FL updated) 
a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=subb alu=rank_8; 

// RAM[SP=SP+1] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl sp=qup 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
lsh81s: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= lsh81 (A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=lshl alu=rank_8; 

// RAM[SP] <= C[7:0 ], MPC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 



914 


Version "D" 


lsh8rs: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= lsh8r(A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=lshr alu=rank_8; 

// RAM[SP] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
ash81s: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= ash81 (A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashl alu=rank_8; 

// RAM[SP] <= C[7: 0] , MPC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
ash8rs: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= ash8r (A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=ashr alu=rank_8; 

// RAM[SP] <= C[7:0] , MPC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
rot8cls: 

// A <= RAM[SP] 



Version "D" 


915 


a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= rot8cl (A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotcl alu=rank_8; 

// RAM[SP] <= C[7:0] , MFC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
rot8crs: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= rot8cr(A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotcr alu=rank_8; 

// RAM[SP] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
rot81s: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= rot81 (A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotl alu=rank_8; 

// RAM[SP] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
rot8rs: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 



916 


Version "D" 


// C <= rot8r(A) (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=rotr alu=rank_8; 

// RAM[SP] <= C[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s 
c=select_bus_a c=bus_write 
addr=fetch jump=true; 
casts_uns: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= A[7:0] (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load c=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8; 

// RAM[SP] <= C[7:0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM[SP+1] <= C[15:8], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 
casts_sig: 

// A <= RAM[SP] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// C <= A[7:0] (FL updated) 

a=select_bus_a a=bus_write 
c=select_bus_b c=register_load c=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8 alu=signed; 

// RAM[SP] <= C[7: 0] 

ram=select_bus_a ram=load ram=s 

c=select_bus_a c=rank_8 c=select_byte_l c=bus_write; 

// RAM [SP+1] <= C[15:8 ], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qpl 
c=select_bus_a c=rank_8 c=select_byte_2 c=bus_write 
addr=fetch jump=true; 



Version "D" 


917 


call: 

// TMP[7:0] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// TMP [15:8] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// RAM[ — SP] <= PC [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
pc=select_bus_a pc=rank_8 pc=select_byte_2 pc=bus_write; 

// RAM[ — SP] <= PC[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
pc=select_bus_a pc=rank_8 pc=select_byte_l pc=bus_write; 

// PC <= TMP, MPC <= #fetch 

pc=select_bus_a pc=rank_l6 pc=register_load 
tmp=select_bus_a tmp=rank_l6 tmp=bus_write 
addr=fetch jump=true; 
call_i : 

// RAM[ — SP] <= PC [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
pc=select_bus_a pc=rank_8 pc=select_byte_2 pc=bus_write; 

// RAM[ — SP] <= PC[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
pc=select_bus_a pc=rank_8 pc=select_byte_l pc=bus_write; 

// PC <= I , MPC <= # fetch 

pc=select_bus_a pc=rank_l6 pc=register_load 
i=select_bus_a i=rank_l6 i=bus_write 
addr=fetch jump=true; 
call_j : 

// RAM[ — SP] <= PC [15: 8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
pc=select_bus_a pc=rank_8 pc=select_byte_2 pc=bus_write; 

// RAM[ — SP] <= PC[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
pc=select_bus_a pc=rank_8 pc=select_byte_l pc=bus_write; 

// PC <= J, MPC <= #fetch 

pc=select_bus_a pc=rank_l6 pc=register_load 
j=select_bus_a j=rank_l6 j=bus_write 
addr=fetch jump=true; 
return: 

// PC[7:0] <= RAM[SP++] 



918 


Version "D" 


pc=select_bus_a pc=rank_8 pc=register_load_byte_l pc=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// PC[15:8] <= RAM[SP++], MPC <= #fetch 

pc=select_bus_a pc=rank_8 pc=register_load_byte_2 pc=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
ivt 1: 

// TMP[7:0] <= RAM[PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_l tmp=select_byte_l 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// TMP [15:8] <= RAM [PC++] 

tmp=select_bus_a tmp=rank_8 tmp=register_load_byte_2 tmp=select_byte_2 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// IVT <= TMP, MPC <= #fetch 

ivt=ivt_load 

tmp=select_bus_a tmp=rank_l6 tmp=bus_write 
addr=fetch jump=true; 

int: 

// 

// push FL 

// 

// RAM[ — SP] <= FL[15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_2 fl=bus_write; 

// RAM[ — SP] <= FL[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_l fl=bus_write; 

// 

// Reset interrupt enable flag 

// 

fl=select_bus_b fl=rank_16 fl=register_load 
alu=cleari; 

// 

// push (PC+1) to jump over the interrupt argument. 

// 

// RAM[ — SP] <= (PC+1)[15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

pc=select_bus_a pc=rank_8 pc=select_byte_2 pc=bus_write pc=qpl; 

// RAM[ — SP] <= (PC+1) [7:0] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

pc=select_bus_a pc=rank_8 pc=select_byte_l pc=bus_write pc=qpl; 



Version "D" 


919 


// 

// Convert the interrupt number from the argument, to the 
// interrupt vector table item address: 

// TMP <= IVT [int ], int <= RAM [PC] 

// 

// TMP <= IVT [RAM [PC] ] 

tmp=select_bus_a tmp=rank_l6 tmp=register_load 
ivt=select_int_b ivt=bus_write 
ram= s e1e ct_bu s_b ram=bus_writ e ram=p; 

// 

// Prepare to call the interrupt routine, loading the 
// interrupt vector table item address into PC. 

// 

// PC[7:0] <= RAM [TMP] 

pc=select_bus_a pc=rank_8 pc=register_load_byte_l pc=select_byte_l 
ram=select_bus_a ram=bus_write ram=t; 

// PC[15:8] <= RAM[TMP+1], MPC <= #fetch 

pc=select_bus_a pc=rank_8 pc=register_load_byte_2 pc=select_byte_2 
ram=select_bus_a ram=bus_write ram=t tmp=qpl 
addr=fetch jump=true; 
iret: 

// 

// Pop PC 

// 

// PC[7:0] <= RAM[SP++] 

pc=select_bus_a pc=rank_8 pc=register_load_byte_l pc=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// PC[15:8] <= RAM[SP++] 

pc=select_bus_a pc=rank_8 pc=register_load_byte_2 pc=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// 

// Pop FL 

// 

// FL[7:0] <= RAM[SP++] 

fl=select_bus_a fl=rank_8 fl=register_load_byte_l fl=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=dpl; 

// FL [15: 8] <= RAM[SP++], MPC <= #fetch 

fl=select_bus_a fl=rank_8 fl=register_load_byte_2 fl=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=dpl 
addr=fetch jump=true; 
imrl: 



920 


Version "D" 


// IRQ <= RAM[PC++], MFC <= #fetch 

irq=irq_mask_load 

ram=select_bus_a ram=bus_write ram=p pc=dpl 
addr=fetch jump=true; 

irq: 

// 

// push FL 

// 

// RAM[ — SP] <= FL[15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_2 fl=bus_write; 

// RAM[ — SP] <= FL[7:0], MPC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_l fl=bus_write; 

// 

// Reset interrupt enable flag 

// 

fl=select_bus_b fl=rank_16 fl=register_load 
alu=cleari; 

// 

// push (PC-1) to jump back to the opcode just read . 

// 

// RAM[ — SP] <= (PC-1) [15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

pc=select_bus_a pc=rank_8 pc=select_byte_2 pc=bus_write pc=qml; 

// RAM[ — SP] <= (PC-1) [7:0] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

pc=select_bus_a pc=rank_8 pc=select_byte_l pc=bus_write pc=qml; 

// 

// Convert the interrupt number from the IRQ module, to the 
// interrupt vector table item address: 

// TMP <= IVT[int], int <= IRQ 

// 

// TMP <= IVT [INT [IRQ] ] 

tmp=select_bus_a tmp=rank_16 tmp=register_load 
ivt=select_int_a ivt=bus_write; 

// 

// Prepare to call the interrupt routine, loading the 
// interrupt vector table item address into PC. 

// 

// PC[7:0] <= RAM [TMP] 



Version "D" 


921 


pc=select_bus_a pc=rank_8 pc=register_load_byte_l pc=select_byte_l 
ram=select_bus_a ram=bus_write ram=t; 

// PC[15:8] <= RAM[TMP+1] 

pc=select_bus_a pc=rank_8 pc=register_load_byte_2 pc=select_byte_2 
ram=select_bus_a ram=bus_write ram=t tmp=qpl; 

// 

// Set the IRQ received as already done, 

// MFC <= #fetch 

irq=irq_done 
addr=fetch jump=true; 
op_error: 

// 

// push FL 

// 

// RAM[ — SP] <= FL[15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_2 fl=bus_write; 

// RAM[ — SP] <= FL[7:0], MFC <= #fetch 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 
fl=select_bus_a fl=rank_8 fl=select_byte_l fl=bus_write; 

// 

// Reset interrupt enable flag 

// 

fl=select_bus_b fl=rank_16 fl=register_load 
alu=cleari; 

// 

// push (PC-1) to jump back to the opcode just read. 

// 

// RAM[ — SP] <= (PC-1)[15:8] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

pc=select_bus_a pc=rank_8 pc=select_byte_2 pc=bus_write pc=qml; 

// RAM[ — SP] <= (PC-1)[7:0] 

ram=select_bus_a ram=load ram=s sp=qml sp=qup 

pc=select_bus_a pc=rank_8 pc=select_byte_l pc=bus_write pc=qml; 

// 

// Convert the interrupt number 0 to the 
// interrupt vector table item address: 

// 

// TMP <= IVT[0] 

tmp=select_bus_a tmp=rank_16 tmp=register_load 
ivt=select_int_b ivt=bus_write 



922 


Version "D" 


bus=bw bus=select_bus_b bus=0; 

// 

// Prepare to call the interrupt routine, loading the 
// interrupt vector table item address into PC. 

// 

// PC[7:0] <= RAM[TMP] 


pc=select_bus_a pc=rank_8 pc=register_load_byte_l 
ram=select_bus_a ram=bus_write ram=t; 

// PC[15:8] <= RAM[TMP+1], MPC <= #fetch 

pc=select_bus_a pc=rank_8 pc=register_load_byte_2 
ram=select_bus_a ram=bus_write ram=t tmp=qpl 
addr=fetch jump=true; 
flag_i_clr: 

// FL <= FL&OxFFEF, MPC <= #fetch 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=cleari irq=irq_done 
addr=fetch jump=true; 
f lag_i_set: 

// FL <= FL10x0010, MPC <= #fetch 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=seti irq=irq_done 
addr=fetch jump=true; 
f lag_c_clr: 

// FL <= FL&OxFFFE, MPC <= #fetch 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=clearc 

addr=fetch jump=true; 
flag_c_set: 

// FL <= FL&OxOOOl, MPC <= #fetch 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=setc 

addr=fetch jump=true; 
in num a: 


pc=select_byte_l 


pc=select_byte_2 


// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// I/O request 

ioc=req; 

// Time to wait. 

ctrl=nop; 

// A <= IOC, MPC <= #fetch 



Version "D" 


923 


a=select_bus_a a=register_load ioc=bus_write 
addr=fetch jump=true; 
in_num_b: 

// IOA <= RAM [PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// I/O request 

ioc=req; 

// Time to wait . 

ctrl=nop; 

// B <= IOC , MFC <= #fetch 

b=select_bus_a b=register_load ioc=bus_write 
addr=fetch jump=true; 
in_num_mi: 

// IOA <= RAM [PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// I/O request 

ioc=req; 

// Time to wait . 

ctrl=nop; 

// RAM [I] <= IOC , MFC <= # fetch 

ram=select_bus_a ram=load ram=i ioc=bus_write 
addr=fetch jump=true; 
in_num_mj: 

// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// I/O request 

ioc=req; 

// Time to wait . 

ctrl=nop; 

// RAM[J] <= IOC , MFC <= #fetch 

ram=select_bus_a ram=load ram=j ioc=bus_write 
addr=fetch jump=true; 
out_a_num: 

// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// IOC <= A 

ioc=load a=select_bus_a a=bus_write; 



924 


Version "D" 


// I/O request, MPC <= #fetch 

ioc=req 

addr=fetch jump=true; 
out_b_num: 

// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// IOC <= B 

ioc=load b=select_bus_a b=bus_write; 

// I/O request, MPC <= #fetch 

ioc=req 

addr=fetch jump=true; 
out_mi_num: 

// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// IOC <= RAM[I] 

ioc=load ram=select_bus_a ram=bus_write ram=i; 

// I/O request, MPC <= #fetch 

ioc=req 

addr=fetch jump=true; 
out_mj_num: 

// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// IOC <= RAM[J] 

ioc=load ram=select_bus_a ram=bus_write ram=j; 

// I/O request, MPC <= #fetch 

ioc=req 

addr=fetch jump=true; 
ifack_jump: 

// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// C <= alu(I/0 isack) (FL updated), if ack MPC <= #jump 

ioc=isack ioc=bus_write 

c=select_bus_b c=register_load c=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8 alu=signed 
addr=jump jump=zero_f; 

// discard argument and load next opcode 



Version "D" 


925 


pc=qp2 pc=qup addr=fetch jump=true; 
ifack_call: 


// IOA <= RAM[PC++] 

ioa=select_bus_a ioa=register_load 
ram=select_bus_a ram=bus_write ram=p pc=dpl; 

// C <= alu(I/0 isack) (FL updated), if ack MPC <= #ifack_call_ok 

ioc=isack ioc=bus_write 

c=select_bus_b c=register_load c=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=a alu=rank_8 alu=signed 
addr=call jump=zero_f; 

// discard argument and load next opcode 

pc=qp2 pc=qup addr=fetch jump=true; 
cmpr: 

// FL(A-B), MPC <= #fetch 

a=select_bus_a a=bus_write a=rank_l6 
b=select_bus_b b=bus_write b=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_l6 
addr=fetch jump=true; 
testr: 


// FL(A&B) , MPC <= #fetch 

a=select_bus_a a=bus_write a=rank_l6 
b=select_bus_b b=bus_write b=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=and alu=rank_l6 
addr=fetch jump=true; 
cmpi: 

// A[7:0] <= RAM[I] 


a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=i; 

// A[15:8] <= RAM[I+1], MPC <= #fetch 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=i i=qpl 

// B[7: 0] <= RAM[J] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=j; 

// B [15: 8] <= RAM[J+l], MPC <= #fetch 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=j j=qpl; 

// FL(A-B), MPC <= #fetch 



926 


Version "D" 


a=select_bus_a a=bus_write a=rank_l6 
b=select_bus_b b=bus_write b=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_l6 
addr=fetch jump=true; 
testi: 

// A[7:0] <= RAM[I] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=i; 

// A[15:8] <= RAM[1+1 ], MFC <= #fetch 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=i i=qpl 

// B[7: 0] <= RAM[J] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram= j; 

// B [15: 8] <= RAM[J+l] , MFC <= #fetch 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=j j=qpl; 

// FL(A&B) , MFC <= #fetch 
a=select_bus_a a=bus_write a=rank_l6 
b=select_bus_b b=bus_write b=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=and alu=rank_l6 
addr=fetch jump=true; 
cmps : 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B[15:8] <= RAM[SP+1] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM[SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM[SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// FL(A-B) , MFC <= #fetch 
a=select_bus_a a=bus_write a=rank_l6 
b=select_bus_b b=bus_write b=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 



Version "D" 


927 


alu=sub alu=rank_l6 
addr=fetch jump=true; 
tests : 

// B[7: 0] <= RAM[SP] 

b=select_bus_a b=rank_8 b=register_load_byte_l b=select_byte_l 
ram=select_bus_a ram=bus_write ram=s; 

// B [15: 8] <= RAM[SP+1 ] 

b=select_bus_a b=rank_8 b=register_load_byte_2 b=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// A[7:0] <= RAM [SP+2] 

a=select_bus_a a=rank_8 a=register_load_byte_l a=select_byte_l 
ram=select_bus_a ram=bus_write ram=s sp=qp2; 

// A[15:8] <= RAM[SP+3] 

a=select_bus_a a=rank_8 a=register_load_byte_2 a=select_byte_2 
ram=select_bus_a ram=bus_write ram=s sp=qp3; 

// FL(A&B) , MPC <= #fetch 
a=select_bus_a a=bus_write a=rank_l6 
b=select_bus_b b=bus_write b=rank_l6 
fl=select_bus_b fl=rank_l6 fl=register_load 
alu=and alu=rank_l6 
addr=fetch jump=true; 
cmp 8i: 

// A <= RAM[I] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=i; 

// B <= RAM[J] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram= j; 

// FL(A-B) , MPC <= #fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_8 
addr=fetch jump=true; 
test8i: 

// A <= RAM[I] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=i; 

// B <= RAM[J] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram= j; 



928 


Version "D" 


// FL(A&B) , MFC <= #fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=and alu=rank_8 
addr=fetch jump=true; 
cmp 8 s: 

// B <= RAM[SP] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// A <= RAM[SP+1 ] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// FL(A-B) , MPC <= #fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=sub alu=rank_8 
addr=fetch jump=true; 
test8s : 

// B <= RAM[SP] 

b=select_bus_a b=register_load 
ram=select_bus_a ram=bus_write ram=s; 

// A <= RAM [SP+1] 

a=select_bus_a a=register_load 
ram=select_bus_a ram=bus_write ram=s sp=qpl; 

// FL(A&B) , MPC <= #fetch 

a=select_bus_a a=bus_write 
b=select_bus_b b=bus_write 

fl=select_bus_b fl=rank_l6 fl=register_load 
alu=and alu=rank_8 
addr=fetch jump=true; 
stop: 

ctrl=stop; 

addr=fetch jump=true; 

// 

end 



Version "D" 


929 


12.16 Macrocode 


As an example, the following listing shows a simple program that 
reads from the keyboard and prints the same text on the virtual 
screen. The keyboard input is read after a hardware interrupt. 


Listing 12.44. Macrocode example for TKGate. 


begin macrocode @ 0 
jump #start 


nop 


interrupt_vector 

_table: 

.short 

0x0025 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0026 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

.short 

0x0024 

default_interrupt_routi 


// CPU opcode error 
// CPU 
// CPU 
// CPU 
// IRQ rtc 
// IRQ keyboard 
// IRQ hard disk 
// IRQ 
// software 
// software 
// software 
// software 
// software 
// software 
// software 
// software 
ne: 


iret 


op_code_error: 

stop 

keyboard: 

in 1 , %A 
equal 

jump %zero,1,#keyboard_end 

out %A,0 

jump #keyboard 


// keyboard read 
// update flags 
// if zero exit 
// print on screen 
// continue 



930 


Version "D" 


keyboard_end: 

iret 


start: 

cp 0x0080, %I 
cp %I, %SP 

// 

ivtl #interrupt_vector_table 

// 

imrl OxOF 
flag_i 1 

// 

keyboard_reset: 

in 1,%A 
equal 

jump %zero,0,#keyboard_reset 

// 


// set stack bottom 


// all IRQ accepted 
// IRQ enabled 

// keyboard read. 

// update flags 

// if not zero continue 


loop: 
stop: 

end 


jump #loop 
stop 


// never reach the end. 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


931 

Version "E" 


Chapter 


« 


13.1 General purpose modules. 934 

13.2 Module “MEM” . 941 

13.2.1 Module “MAR” . 942 

13.2.2 Module “MIR”. 944 

13.2.3 Module “MDR” . 945 

13.3 General purpose registers. 946 

13.4 Module “ALU” and related submodules. 950 

13.5 Module “BUS” . 958 

13.6 Module “IRQ”. 959 

13.7 Module “IVT”. 961 

13.8 Module “RTC”: real time clock. 962 

13.9 Module “TTY” . 963 

13.10 Module “HDD” . 968 

13.11 Module “CTRL”. 974 

13.11.1 Modules “Fw”. 975 

13.11.2 Module “CLK_CLR” . 977 

13.12 Memory and microcode fields. 978 

13.13 Opcodes . 983 

13.14 Microcode. 1019 

13.15 Macrocode. 1058 






















932 


Version "E" 


This version of the project is made to resolve the memory access 
problem previously evidenced. There is a module MEM that in¬ 
cludes the MAR register for the address, the MIR register (memory 
instruction register , ex IR) and a renewed MDR register. To access 
the memory, it is required to put the address inside the MAR register, 
specifying the size (rank) and the direction (read or write); then the 
read or write starts and stops automatically. But this process requires 
three clock cycles for 16-bit rank and two clock cycles for 8-bit rank. 
As the register MAR is restored and it is necessarily traversed by the 
data read from or written to the RAM memory, the rank adaptation 
functions are carried out by MDR and the other registers do not need 
that adaptation anymore. 


Attachments 

Description 

attachments/xcpu/xcpu-e. v 

TKGate Verilog netlist source file. 

attachments/xcpu/xcpu-e. gm 

TKGate microcode and 

macrocode source file. 

attachments/xcpu/xcpu-e- 

terminal.vpd.tcl 

TCL/Tk script related to the termi¬ 
nal module TTY . 








Version "E" 


933 


Figure 13.2. Simple CPU, version “E”. 










































































































































































934 


Version "E" 


13.1 General purpose modules 

The following modules were already used on the previous version 
of the project, except vrl , which is a counter able to increment or 
decrement only by 2" values. 


Figure 13.3. Size reduction module: the module RANK and its 
submodules. 



Do 






















































Version "E" 


935 


Figure 13.4. Building Dn modules. 


p > 


Ck > 


D > 


C > 



Q Q 
















































































































































936 


Version "E" 


Figure 13.5. Building DR n modules. 


D 

V 



Q 














































































Version "E" 


937 


Figure 13.6. Building DHw modules. 


D 

V 



Q 

































































































938 


Version "E" 


Figure 13.7. Building vr n modules. 












































































































Version "E" 


939 


Figure 13.8. Building VRw modules. 







940 


Version "E" 


Cqo 


Cdo 


Q ^ 


D 

V 

f 



D 

L 

qil 

◄- 

Cqo 


qi 


Cdo 

VR1 

di 

4 - 

Cqi 

4 - 

%k 

P 

Cdi 

C 


A 

Ck 


A 

P 


V qil 

V 


module VR2 


D L qil 
Cqo qi 

Cdovm c^i 

Q - 
ck P C 


A 

C 


"7 


z 


■<qi 


<Cqi 

-<Cdi 





























































Version "E" 


941 


Cqo '* s S~ 


Cdo 


Q 


D 

V 

I 


2 


3:2 

1:0 


/ 


/ / 2 


D 

Cqo 

L 

qil 

qi 

2 

** 



VR2 

di 

4 - 

oao 

Cqi 

<- 


P 

Cdi 

C 

4 - 


A 

Ck 


A 

P 


V qil 
V 


2 

ft 


~7 


module VR4 




D L 
Cqo 


qil. 
qi 

Cdo VR2 c^j 
Q - ^i 
Ck P C 






A 

C 


3:2 

1:0 


4 


qi 


3:2 


/ 


/ 


1:0 


Z, 


~~7 

■< Cqi 
■<Cdi 


■<di 


13.2 Module "MEM" 

The most important feature of this version is related to the memory 
management: the new module MEM contains the registers MAR , 
MDR and MIR which were previously autonomous. 



























































942 


Version "E" 


Figure 13.9. The module MEM. 



13.2.1 Module "MAR" 


To access the RAM it is necessary to specify the address of the first 
byte, the rank starting from that address and the direction (read or 
write). First it is the MAR module involved. 





































































































Version "E" 


943 


Figure 13.10. Module MAR. 

Rank 

V 



RAM_A b RAM_WE RAM_OE 


Inside the above figure, should be noticed the register used to store 
the memory address (on the left, type DR16). In the middle, the reg¬ 
ister of type vr2 is responsible to hold and count the rank: 0 means 
one byte; 1 means two bytes; -1 (11 2 ) means “stop”. The middle 
register is not reset, but preset, so its initial condition is equal to the 
value -1. 

When the rank counter is not equal to -1 (11 2 ), then it is automati¬ 
cally decremented at each clock; after the rank counter reaches the 
0, it becomes equal to -1 and it stops changing. That is: when the 
requested rank is 1 (meaning two bytes), its first value is 1, then 0, 





















































944 Version "E" 

then -1. When the rank counter is loaded with a valid rank it be¬ 
comes busy and the output Busy is used to transmit this notion to 
the other modules (MDR and MIR); at the same time, the latch on 
the right (type DH1) holds the value received from the input W. 

The output RAM_A is obtained as the sum of the original address 
received from input Addr and the rank value, reported by the rank 
counter. That is: the first address output by Addr is the highest. 
The output b is used to let know the other modules which byte of 
the selected rank is considered during a particular time. The output 
RAM_OE is asserted (0 as the meaning is complemented) when the 
RAM is to be written, the busy line is active and the clock signal is 
low. 

The output RAM_OE is asserted (0 as the meaning is comple¬ 
mented) when the RAM is to be read: the output is negated (1) only 
when a write request is received. 


The RAM memory allows to be read in any condition, but when 
it comes the time to write in it, it is necessary to activate the WE 
input only when the address is already available: that is why it is 
allowed to write only when the clock is low, as no change on the 
address can happen. 


13.2.2 Module "MIR" 

The MIR module (i memory instruction register) is responsible for 
reading from memory the next opcode to be executed. The current 
opcode occupy only one byte, but the MIR is prepared to accept a 
larger size: the b (byte) input line selects the byte that is currently 






Version "E" 


945 


read (the rank is specified to the MAR module). The RAM_OE input 
line is asserted when the RAM is read and the Busy line is active 
when the RAM access cycle is not yet finished. The input line R 
should be active when the MIR module should read from RAM; 
then, when the read cycle starts, the Busy becomes active and the 
read request is hold by the DH1 module, up to the cycle end. 


Figure 13.11. Module MIR . 



13.2.3 Module "MDR" 


The MDR module is a register used as buffer between the RAM 
memory and the CPU data bus. The difference from the MIR mod¬ 
ules depends on the fact that it is connected to the two data busses 
and that can also write to the RAM. The MDR module is also re¬ 
sponsible for rank adaptation of data, before writing to the data bus. 






















































946 


Version "E" 


Figure 13.12. Module MDR . 



13.3 General purpose registers 


The registers are made in a simpler way compared to the previous 
version, because there is no rank problem: all data is moved at a 16- 
bit rank. There are two types of registers: the following figure shows 
the two external layouts. 


























































































Version "E" 


947 


Figure 13.13. 16-bit registers: external appearance. 


| d register content copy 


4 

fc" 




^ 15:0 connection to the "A” bus / 

! ^i5 o connection from the ALU 


t 3 o test for debugging 

\ ^ 15:0 connection to the "B" bus 


c o clear 
c i clock 


D 


B 


T 



M) bus select: 0=A; 1 =B 

C\ bus write 

Q load register 
Q:3 pre-increment: -S..+7 

Q pre-increment update 
Qi:s post-increment: -S.. + 7 





















948 


Version "E" 


Figure 13.14. 16-bit registers: internal structure. 



o o 

A B 


The C and FL registers are made with a slightly different module, 
where the “B” bus connection is named alu and it is only able to 
receive data. 





























































































Version "E" 


949 


Figure 13.15. Alternative 16-bit registers structure. 






















































































950 Version "E 

13.4 Module "ALU" and related submodules 


The module ALU, is the same as the previous version. 


Figure 13.16. Module ALU. 



The other components inside the ALU module are just the same as 
the previous version. 












































































































































Version "E" 


951 


Figure 13.17. Module LOGIC : the logic unit. 


A 

V 



DQ> 




















































952 


Version "E" 


Figure 13.18. Module AS: addition and subtraction 













































Version "E" 


953 


Figure 13.19. Modules FAn : w-bit full adder. 



V 

S 


<Ci 


<03 








































































sh _left_and_carry_left_16 


954 


Version "E" 


Figure 13.20. Module SH: bit shift. 



6 


U 






la [ 

D 1 

Ir 

Lo 


Li 


SH8 


Ri 


Ro 

C 

) 

c 






6 


la 

D 

Ir 


Lo 

SH8 

Li 

◄- 

Ri 



Ro 

-► 

C 

) 


S 



sh left and carry l( ;ft 8 


/ 8 


use_previous_carry 


□ 




-<Ci 


sh_right_and_carry_right 


D 


Y | 

Col 6 016 


I 

S 


Y 

08 


V 

Co8 


<C 






































































Version "E" 


955 


Figure 13.21. Module ROT : bit rotation. 



The modules SHn are one-bit logic or arithmetic shifter. It all starts 
from module SHI , as the following figure shows. 























































956 


Version "E" 


Figure 13.22. Module SHn : one-bit logic or arithmetic shift. 



[1] Arithmetic shift conditions: 

- the requested shift is arithmetic; 

- the requested shift is to the right; 

- the most significant bit value is one. 

[2] Overflow conditions: 

- the requested shift is arithmetic; 

- the requested shift is to the left; 

- the most significant bit value is changed. 


la 

V 


D 

V 


//2 module SH2 


Lo 


Ri >- 


r 


V 

o 


la 

v 


Lo 


Ri >- 


o 


J 


A) 2 
s 


D 

V 



/ . 

/ 

4 


module SH4 


4 

/ / Z 


rt2 
ro o 


lr 

V 



1; 

a 

D 

lr 


la 

D 

lr 

◄- 

Lo 


SHI 

Li 

◄- 

◄- 

Lo 

SHI 

Li 

-► 

Ri 



Ro 

-► 

-► 

Ri 


Ro 


0 


S 



0 


S 


lr 

v 


I; 

a D lr 


la D lr 


Lo 

Li 

◄- ◄- 

Lo Li 

4- 


SH2 


SH2 


Ri 

Ro 

-► -► 

Ri Ro 

-► 

C 

) S 


0 S 



— <Li 
->■ Ro 


—<Li 
->■ Ro 

























































































Version "E" 


957 


c> 


Figure 13.23. Module FSR : flags set-reset. 


Fi 

V 



V 

Fo 










































































« 


958 

13.5 Module "BUS" 


Version "E" 


The module BUS is used to let the control unit put a value inside the 
data-bus. This module BUS is the same as the previous version. 

Figure 13.24. Module BUS. 


bus write 



Y 

B 


V 

A 


























Version "E" 


959 


13.6 Module "IRQ" 

The IRQ module is the same as the previous version. All the de¬ 
tails about the module functionality should be found at the previous 
version description. 


irq_register 


960 


Version "E" 


Figure 13.25. Module IRQ. 


05 























































































































































Version "E" 


961 


13.7 Module "IVT" 

The IVT module is the same as the previous version. All the de¬ 
tails about the module functionality should be found at the previous 
version description. 

Figure 13.26. Module IVT. 

la lb 

V V 


« 


C>~ 


2 

7 ^ 


IVT start address 


clock 


clear 


J5 


16 


Ck, 


DR16 l 


Q 


interrupt select 


zT 


interrupt 


1 


H6 


/ 7 16 

jnterrupt_x_2 


A B 
Co FA16 Ci 
O e 


T 


+ 

V 16 


load 


v- 


D 


bus write 


0 

A 


/— <C 


V 


V 










































962 

13.8 Module "RTC": real time clock 


Version "E" 


The RTC module (real time clock ) is just the same as the previous 
version: it generates a 1 Hz impulse, producing the hardware inter¬ 
rupt IRQO. All the details about the module functionality should be 
found at the previous version description. 


Listing 13.27. Module RTC : Verilog declaration. 


module RTC (T); 


output T; 


reg p; 


always 


begin 


p = 0; 


$tkg$wait 

(500) ; 

P = i; 


$tkg$wait 

(500); 

end 


assign T = p; 


endmodule 




Version "E" 


963 


13.9 Module "TTY" 

« 


The TTY module is just the same as the previous version: it is a 
textual screen-keyboard terminal interface. All the details about the 
module functionality should be found at the previous version de¬ 
scription. 


Figure 13.28. Module TTY. 


























































































































Listing 13.29. Module terminal : Verilog code. 

module terminal(K_DATA, K_REQ, K_ACK, 

S_DATA, S_REQ, S_ACK, CLR) 

output K_ACK; 
output S_ACK; 
output [7:0] K_DATA; 
input [7:0] S_DATA; 
input K_REQ; 
input S_REQ; 
input CLR; 
reg k_ready; 
reg [7:0] key; 
reg s_ready; 

initial 
begin 

k_ready = 0; 
s_ready = 0; 
key = 0; 
end 

always 
begin 

@(posedge CLR) 
k_ready = 0; 
s_ready = 0; 
key = 0; 
end 



Version "E 


initial $tkg$post("TERMINAL", 

always 

begin 

@ (posedge K_REQ); 

# 5; 

key = $tkg$recv("%m.KD") ; 

# 5; 

k_ready = 1'b1; 

# 5; 

@ (negedge K_REQ); 

# 5; 

k_ready = 1'bO; 
end 

always 

begin 

@ (posedge S_REQ); 

# 5; 

$tkg$send("%m.SD",S_DATA) 

# 5; 

s_ready = l'bl; 

# 5; 

@ (negedge S_REQ); 

# 5; 

s_ready = 1'bO; 
end 


assign S_ACK = s_ready; 




966 


Version "E" 


assign K_DATA = key; 
assign K_ACK = k_ready; 

endmodule 


Listing 13.30. File ‘share/tkgate/vpd/terminal. tel’ for 

TCL interface. _ 

image create bitmap txteurs -file "$bd/txtcurs.b" 

VPD::register TERMINAL 
VPD::allow TERMINAL::post 
VPD::allow TERMINAL::data 

namespace eval TERMINAL { 

# Public variables declarations: the variables $terminal_... 

# are arrays of which only the element $n is used; 

# that element identifies uniquely the working interface instance. 

variable terminal_w 
variable terminal_pos 

# 

variable KD 

# Function requested by TKGate to create the interface. 

proc post {n} { 

variable terminal_w 
variable terminal_pos 

# Create the window and save the object element in a $terminal_w array element. 

set terminal_w($n) [VPD::createWindow "TERMINAL $n" -shutdowncommand "TERMINAL::unpost $n" ] 

# For convenience, copy the object reference inside the local 

# variable $w; then, the variable $w will be used as a reference to the object. 

set w $terminal_w($n) 
text $w.txt -state disabled 
pack $w.txt 

# Put the cursor at the end of the displayed text. 

$w.txt image create end -image txteurs 

# Bind the keyboard input, related to the object represented by 

# $terminal_w ($n), to the function sendChar. 

bind $w <KeyPress> "TERMINAL::sendChar $n \"%A\"" 

# Open a reading channel, named «SD» (screen data), 

# and associate it to the function «data»; moreover, open a 

# writing channel, named «KD» (keyboard data). 

if {[info exists ::tkgate_islnitialized]} { 

VPD::outsignal $n.KD TERMINAL::KD($n) 

VPD::insignal $n.SD -command "TERMINAL::data $n" -format %d 

} 

# Reset the character count, used to count the characters displayed 

# on screen. 

set terminal_pos($n) 0 





Version "E" 


967 


} 

# Function that receives the typing and put It Into the 

# channel «KD», related to the current Interface Instance. 

proc sendChar {n key} { 
variable KD 

if { [string length $key ] == 1 } { 
binary scan $key c c 
set TERMINAL::KD($n) $c 

} 

} 

# Function that TKGate requires to destroy the Interface. 

proc unpost {n} { 

variable terminal_w 
variable terminal_pos 
destroy $terminal_w($n) 
destroy $terminal_pos($n) 
unset terminal_w($n) 
unset terminal_pos($n) 

} 

# Function used to get the data to display on screen. 

proc data {n c} { 

variable terminal_w 
variable terminal_pos 

# For convenience, copy the object reference representing the 

# Interface, Inside the variable $w. 

set w $terminal_w($n) 
catch { 

# The variable $c contains the character to display. 

if { $C == 7 } { 

# BEL 

bell 

return 

} elseif { $c == 127 | | $c == 8 } { 

# DEL I BS 

if { $terminal_pos($n) > 0 } { 

# Delete the last displayed character, but only If the 

# characters counter Is greater than zero, otherwise 

# the cursor would disappear and the next characters 

# would be located In an Invisible screen area. 

$w.txt configure -state normal 
$w.txt delete "end - 3 chars" 

$w.txt see end 

$w.txt configure -state disabled 

set terminal_pos($n) [expr {$terminal_pos($n) - l}] 

} 

return 

} elseif { $c == 13 } { 

# Convert CR to LF. 

set c 10 

} 

# Convert the character number Into a visible symbol. 

set x [format %c $c] 



968 


Version "E" 


# Display the symbol . 

$w.txt configure -state normal 
$w.txt insert "end - 2 chars" $x 
$w.txt see end 

$w.txt configure -state disabled 

# Update the displayed characters counter. 

set terminal_pos($n) [expr {$terminal_pos($n) + l}] 

} 

} 

} 


13.10 Module "HDD" 

The HDD module is just the same as the previous version: it is a 
simulated mass-memory drive with the ability to handle eight units. 
All the details about the module functionality should be found at the 
previous version description. 



Version "E" 


969 


Figure 13.31. Module HDD. 



A 


Listing 13.32. Verilog code describing the module hd. 


module 

hd(DRIVE, SECTOR, 

BYTE, 

WRITE, DATA_IN, 


DATA_OUT, REQ, 

ACK, 

CLR) ; 

input 

[2:0] DRIVE; 



input 

WRITE, REQ, CLR; 



input 

[15:0] SECTOR; 



input 

[9:0] BYTE; 



input 

[7:0] DATA_IN; 



















































































































970 


Version "E" 


output [7:0] DATA_OUT; 
output ACK; 

// 

integer _data_out; 
integer _ack; 

// 


reg [7:0] buffer[0:1023]; 
reg [8*24-1:0] filename = 

// 


integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

// 


i; 

sector_8; 
sector_7 ; 
sector_6; 
sector_5; 
sector_4 ; 
sector_3; 
sector_2; 
sector_l ; 
sector_0; 
x; 


n hd0_sector_000000000.mem"; 


initial 

begin 

for (i=0; i<1024; i=i+l) 
begin 

// 

// Initial buffer reset with 00. 

// 


buffer[i] = 8'h00; 

end 

ack = 0; 



Version "E" 


971 




972 


Version "E" 


sector_3 - x%10; 
x = x /10; 
sector_4 - x%10; 
x = x /10; 
sector_5 = x%10; 
x = x /10; 
sector_6 = x%10; 
x = x /10; 
sector_7 - x%10; 
x = x /10; 
sector_8 = x%10; 

// 

// The string starts from the right side and 
// continues to the left! 

// 


filename[12*8+7 

: 12 * 

8] 

= sector 

_8 

+ 

8'd48; 

filename[11*8+7 

: 11* 

8] 

= sector 

_7 

+ 

• s. 

00 

T5 

00 

filename[10*8+7 

: 10* 

8] 

= sector 

_6 

+ 

• s. 

00 

00 

filename[9*8+7: 

9*8] 

= 

sector_5 

+ 

8' 

d4 8; 

filename[8*8+7: 

8*8] 

= 

sector_4 

+ 

8' 

d4 8 ; 

filename[7*8+7 : 

7*8] 

= 

sector_3 

+ 

8' 

d4 8 ; 

filename[6*8+7 : 

6*8] 

= 

sector_2 

+ 

8' 

d4 8 ; 

filename[5*8+7 : 

5*8] 

= 

sector_l 

+ 

8' 

d4 8 ; 

filename[4*8+7 : 

4*8] 

= 

sector_0 

+ 

8' 

d4 8 ; 

// 







filename[21*8+7 

: 21* 

8] 

= DRIVE • 

+ 8 

' d.4 8 ; 


// 

if (WRITE) 
begin 

// 

// Put data inside the buffer. 



Version "E" 


973 


// 

buffer[BYTE] = DATA_IN; 

// 

// Save the buffer to disk. 

// Please remember that $writememh() 
// must be enabled inside 
// TKGate configuration! 

// 

$writememh(filename, buffer); 

// 

// Return the same data read. 

// 

_data_out = buffer[BYTE]; 
end 
else 
begin 

// 

// Get data from disk to the buffer. 

// 

$readmemh(filename, buffer); 

// 

// Return the data required. 

// 

_data_out = buffer[BYTE]; 
end 

// 

// Acknowledge. 

// 

_ack = 1; 

// 

// Wait the end of request 



974 


Version "E" 


// (the negative edge) 

// before restarting the loop. 

// 

@(negedge REQ); 

# 10 ; 

// 

// Now become ready again. 

// 

_ack = 0; 
end 

// 

assign DATA_0UT = _data_out; 
assign ACK = _ack; 

// 

endmodule 


13.11 Module "CTRL 77 

The module CTRL is almost the same as the previous version, ex¬ 
cept for the /iPC size, which is now 11 bits. 



Version "E" 


975 


Figure 13.33. Module CTRL. 


interrupt set ^ 



'5 

Is interrupt enable 

T 

11 


I 

Dr- 


0x423 



13.11.1 Modules "Fw 


The modules Fn , used as frequency divisors, are made in the same 
way as in the previous version. 





















































































































976 


Version "E" 


Figure 13.34. Modules D1 and 77: building a T flip-flop from a 
D flip-flop. 

module Dl: positive edge D flip-flop p y module Tl: Tflip-flop 



Figure 13.35. Building the F n modules. 

module FI 



A 

C 


























































































































Version "E" 


977 


13.11.2 Module "CLK_CLR" 

The module CLKJCLR is responsible for the clock pulse generation 
and for the reset line, which is to be synchronized with the clock. The 
clock frequency may be controlled by the dip-switch at the top. It is 
important to recall that the control unit receives an inverted clock 
pulse, because the microcode data should be ready before the clock 
positive edge. This one is just the same as the previous version. 


Figure 13.36. Module CLKJCLR. 





































































978 


Version "E" 


Figure 13.37. Module onejup , used to start the oscillation inside 
the module CLK_CLR. 

module one_up #(.W(1000)) (Z) ; 

output Z; 
reg Z; 

initial 

begin 

Z = 1'bO; 

$tkg$wait (W); 

Z = l'bl; 
end 

endmodule 

13.12 Memory and microcode fields 

The memory for this version of the project is described by the fol¬ 
lowing lines of TKGate code. There are many blocks of memory 
for the microcode word, because every component connected to the 
data-bus can be controlled independently, as it is for the previous 
version of the project. 



Version "E" 


979 


Listing 13.38. Memory banks description for TKGate. 


map 

bank[9:0] 

Ctrl.map; 

microcode 

bank[31:0] 

Ctrl.microO; 

microcode 

bank [63:32] 

Ctrl.micro1; 

microcode 

bank [95:64] 

Ctrl.micro2; 

microcode 

bank[127:96] 

Ctrl.micro3; 

microcode 

bank[159:128] 

Ctrl.micro4; 

microcode 

bank [191:160] 

Ctrl.micro5; 

microcode 

bank [223:192] 

Ctrl.micro6; 

macrocode 

bank [15:0] 

ram; 


Listing 13.39. Fields of the microcode word, for TKGate. 


field Ctrl[1:0] 
field jump[5:2] 


field addr[16:6] 

// 

field mar[22:17] 


// 

field mdr[28:23] 


// 

field mir[29:29] 

// 

field pc[41:30] 


= {nop=0, stop=l, load=2}; 

= {false=0, carry_t=l, zero_t=2, negative_t=3, 
overflow_t=4, irq_enabled_t=5, true=6 , 
carry_f : = 9 , zero_f= 10, negat ive_f=11 , 
overflow_f=12, irq_enabled_f=13}; 

= {ciao=0}; 

= {load=0x0001, ram_write=0x0002, 
rank8 = 0 , rankl6=0x0 0 04 , 
p=0, i=8, j = 16, s=24, t=32}; 

= {a=0x0000, b=0x0001, bw=0x0002, 

rank8u=0 , rankl6=0x0 0 04, rank8s=0x0008, 
load=0x0010 T ram_read=0x0 02 0}; 

= {ram_read=0x000l}; 

= {a=0x0000, b=0x0001, bw=0x0002, load=0x0004, 

qpl=0x0008, qp2=0x0010, qp3=0x0018, qp4=0x0020, 
qp5=0x0028, qp6=0x0030, qp7=0x0038, qm8=0x0040, 
qm7=0x0048, qm6=0x0050, qm5=0x0058, qm4=0x0060, 
qm3=0x0068, qm2=0x0070, qml=0x0078, qup=0x0080, 
dpl=0x0100, dp2=0x0200, dp3=0x0300, dp4=0x0400, 
dp5=0x0500, dp6=0x0600, dp7=0x0700, dm8=0x0800. 




980 


Version "E" 




dm7=0x0900. 

dm6=0x0A0 0, dm5 = 0x0B0 0, 

dm4=0x0C00, 



dm3=0x0D00, 

dm2 = 0x0E0 0, dml = 0x0F0 0 

}; 

// 





// Macro for instruction fetch . 



// MAR <= PC++, 

MIR <= RAM 



// fl: 

mar=p mar=rank8 mar=load pc=dpl mir=ram_read; 


// 





field 

fetch[41: 

17] = {f1=0x201001} 

r 


// 





field 

i[53:42] 

= {a=0x0000, b= 

0x0001, bw=0x0002, load 

=0x0004, 



qp1=0x0008, 

qp2=0x0010, qp3=0x0018, 

qp4=0x0 02 0, 



qp5=0x0028. 

qp6=0x0030, qp7=0x0038, 

qm8=0x0040. 



qm7=0x0048, 

qm6=0x0050, qm5=0x0058, 

qm4=0x0060. 



qm3=0x00 68, 

qm2 = 0x0070, qm1 = 0x0078, 

qup=0x0080. 



dp1=0x0100, 

dp2=0x0200, dp3=0x0300. 

dp4=0x0400. 



dp5=0x0500, 

dp6=0x0600, dp7=0x0700. 

dm8=0x0800. 



dm7=0x0900. 

dm6=0x0A0 0, dm5 = 0x0B0 0, 

dm4=0x0C0 0, 



dm3=0x0D00, 

dm2=0x0E00, dml=0x0F00 

}; 

// 





field 

j[65:54] 

= {a=0x0000, b= 

: 0x0001, bw=0x0002, load 

=0x0004, 



qp1=0x0008, 

qp2=0x0010, qp3=0x0018. 

qp4=0x0020. 



qp5=0x0028. 

qp6=0x0030, qp7=0x0038. 

qm8=0x0040. 



qm7=0x0048. 

qm6=0x0050, qm5=0x0058, 

qm4=0x0060. 



qm3=0x00 68, 

qm2 = 0x0070, qm1 = 0x0078, 

qup=0x0080. 



dpl=0x0100. 

dp2=0x0200, dp3=0x0300, 

dp4=0x0400. 



dp5=0x0500, 

dp6=0x0600, dp7=0x0700, 

dm8=0x0800. 



dm7=0x0900. 

dm6=0x0A0 0, dm5 = 0x0B0 0, 

dm4=0x0C0 0, 



dm3=0x0D00, 

dm2 = 0x0E0 0, dml = 0x0F0 0 

}; 

// 





field 

sp [ 7 7 : 6 6 ] 

= {a=0x0000, b= 

: 0x0001, bw=0x0002, load 

=0x0004, 



qpl=0x0008. 

qp2=0x0010, qp3=0x0018, 

qp4=0x0020, 



qp5=0x0028. 

qp6=0x0030, qp7=0x0038, 

qm8=0x0040. 



qm7=0x0048. 

qm6=0x0050, qm5=0x0058, 

qm4=0x0060. 



qm3=0x00 68, 

qm2 = 0x0070, qm1 = 0x0078, 

qup=0x0080. 



dp1=0x0100, 

dp2=0x0200, dp3=0x0300. 

dp 4 = 0x0400, 



dp5=0x0500, 

dp6=0x0600, dp7=0x0700, 

dm8=0x0800. 



dm7=0x0900. 

dm6=0x0A0 0, dm5 = 0x0B0 0, 

dm4=0x0C00, 



dm3=0x0D00, 

dm2=0x0E00, dml=0x0F00 

}; 

// 





field 

tmp[89:78 

] = {a=0x0000, b= 

: 0x0001, bw=0x0002, load 

=0x0004, 



Version "E" 


981 




qp1=0x0008, 

qp2=0x0010. 

qp3=0x0018. 

qp4=0x0020, 



qp5=0x0028. 

qp6=0x0030, 

qp7=0x0038. 

qm8=0x0040. 



qm7=0x0048. 

qm6=0x0050, 

qm5=0x0058. 

qm4=0x0060. 



qm3=0x00 68, 

qm2=0x0070. 

qml=0x0078. 

qup=0x0080. 



dp1=0x0100, 

dp2=0x0200. 

dp3=0x0300. 

dp 4 = 0x0400, 



dp5=0x0500. 

dp6=0x0600. 

dp7=0x0700, 

dm8=0x0800. 



dm7=0x0900. 

dm6=0x0A00, 

dm5=0x0B00, 

dm4=0x0C00, 



dm3=0x0D00, 

dm2=0x0E00, 

dml=0x0F00 

}; 

// 






field 

fl[101:90] 

= {a=0x0000, b 

=0x0001, bw= 

0x0002, load : 

=0x0004, 



qp1=0x0008, 

qp2=0x0010. 

qp3=0x0018. 

qp4=0x0 02 0, 



qp5=0x0028. 

qp6=0x0030. 

qp7=0x0038, 

qm8=0x0040, 



qm7=0x0048. 

qm6=0x0050. 

qm5=0x0058. 

qm4=0x0060, 



qm3=0x00 68, 

qm2=0x0070. 

qml=0x0078. 

qup=0x0080. 



dpl=0x0100. 

dp2=0x0200. 

dp3=0x0300. 

dp4=0x0400. 



dp5=0x0500, 

dp6=0x0600. 

dp7=0x0700. 

dm8=0x0800. 



dm7=0x0900. 

dm6=0x0A00, 

dm5=0x0B00, 

dm4=0x0C0 0, 



dm3=0x0D00, 

dm2=0x0E00, 

dml=0x0F00 

}; 

// 






field 

c[113:102] 

= {a=0x0000, b : 

=0x0001, bw= 

0x0002, load : 

=0x0004, 



qpl=0x0008. 

qp2=0x0010. 

qp3=0x0018. 

qp4=0x0020. 



qp5=0x0028. 

qp6=0x0030. 

qp7=0x0038. 

qm8=0x0040. 



qm7=0x0048. 

qm6=0x0050. 

qm5=0x0058. 

qm4=0x0060, 



qm3=0x00 68, 

qm2=0x0070. 

qml=0x0078. 

qup=0x0080, 



dpl=0x0100. 

dp2=0x0200. 

dp3=0x0300. 

dp4=0x0400, 



dp5=0x0500, 

dp6=0x0600. 

dp7=0x0700. 

dm8=0x0800. 



dm7=0x0900. 

dm6=0x0A00, 

dm5=0x0B00, 

dm4=0x0C0 0, 



dm3=0x0D00, 

dm2=0x0E00, 

dml=0x0F00 

}; 

// 






field 

alu[122:114] 

= {rank8u=0, rank8s=l, rank!6=2. 




a=0, and=4. 

or=8, xor=12. 




nxor=16, nor=20, nand=24, not=28. 




add=64, sub 

=68, addc=72 

, subb=76. 




lshl=128, lshr=132, ashl=136, ashr= 

140, 



rotcl=144, 

rotcr=148. 





rot1=192, rotr=l9 6, 





clearc=256. 

clearz=2 60, 

clearn=2 64, 




clearo=2 68, 

cleari=272. 





setc=288, setz=292, setn=296. 




seto=300, seti=304}; 





982 


Version "E" 


// 





field 

a[134:123] 

= {a=0x0000, b= 

=0x0001, bw=0x0002, load 

=0x0004, 



qpl=0x0008. 

qp2=0x0010, qp3=0x0018. 

qp4=0x0020. 



qp5=0x0028. 

qp6=0x0030, qp7=0x0038. 

qm8=0x0040. 



qm7=0x0048, 

qm6=0x0050, qm5=0x0058, 

qm4=0x0060. 



qm3=0x0068, 

qm2 = 0x0070, qm1 = 0x0078, 

qup=0x0080. 



dp1=0x0100, 

dp2=0x0200, dp3=0x0300, 

dp4=0x0400. 



dp5=0x0500, 

dp6=0x0600, dp7=0x0700. 

dm8=0x0800. 



dm7=0x0900. 

dm6=0x0A0 0, dm5 = 0x0B0 0, 

dm4=0x0C0 0, 



dm3=0x0D00, 

dm2 = 0x0E0 0, dml = 0x0F0 0 

}; 

// 





field 

b[14 6:135] 

= {a=0x0 000, b= 

= 0x0001, bw=0x0002, load : 

=0x0004, 



qp1=0x0008, 

qp2=0x0010, qp3=0x0018, 

qp4=0x0020, 



qp5=0x0028. 

qp6=0x0030, qp7=0x0038. 

qm8=0x0040. 



qm7=0x0048. 

qm6=0x0050, qm5=0x0058. 

qm4=0x0060. 



qm3=0x00 68, 

qm2 = 0x0070, qm1 = 0x0078, 

qup=0x0080. 



dp1=0x0100, 

dp2=0x0200, dp3=0x0300, 

dp 4 = 0x0400, 



dp5=0x0500, 

dp6=0x0600, dp7=0x0700, 

dm8=0x0800. 



dm7=0x0900, 

dm6=0x0A0 0, dm5 = 0x0B0 0, 

dm4=0x0C00, 



dm3=0x0D00, 

dm2 = 0x0E0 0, dml = 0x0F0 0 

}; 

// 





field 

bp[158:147] 

= {a=0x0000, b= 

=0x0001, bw=0x0002, load 

=0x0004, 



qp1=0x0008, 

qp2=0x0010, qp3=0x0018, 

qp4=0x0 02 0, 



qp5=0x0028, 

qp6=0x0030, qp7=0x0038, 

qm8=0x0040. 



qm7=0x0048, 

qm6=0x0050, qm5=0x0058, 

qm4=0x0060. 



qm3=0x0068. 

qm2 = 0x0070, qm1 = 0x0078, 

qup=0x0080. 



dpl~0x0100 f 

dp2=0x0200, dp3=0x0300. 

dp4=0x0400. 



dp5=0x0500 A 

dp6=0x0600, dp7=0x0700, 

dm8=0x0800. 



dm7=0x0900 T 

dm6=0x0A0 0, dm5 = 0x0B0 0, 

dm4=0x0C0 0, 



dm3=0x0D00, 

dm2=0x0E00, dml=0x0F00 

}; 

// 





field 

bus[176:159] 

{bw=0xl0000. 

a=0, b=0x20000}; 


// 





field 

ioa[188:177] 

= {a=0x0000, b= 

=0x0001, bw=0x0002, load 

=0x0004, 



qpl=0x0008. 

qp2=0x0010, qp3=0x0018. 

qp4=0x0020. 



qp5=0x0028, 

qp6=0x0030, qp7=0x0038. 

qm8=0x0040. 



qm7=0x0048 T 

qm6=0x0050, qm5=0x0058. 

qm4=0x0060. 



qm3=0x0068 T 

qm2=0x0070, qml=0x0078. 

qup=0x0080. 



dpl~0x0100 f 

dp2=0x0200, dp3=0x0300. 

dp4=0x0400. 



dp5=0x0500 A 

dp6=0x0600, dp7=0x0700. 

dm8=0x0800. 



Version "E" 


983 


// 

field 

ivt[191:189] 

\—1 

II 

£ 

II 

// 

field 

irq[194:192] 

\ —i 

II 

£ 

II 

// 

field 

ioc[198:195] 

= {load=l 


dm7=0x0900, dm6=0x0A00, dm5=0x0B00, dm4=0x0C00, 
dm3=0x0D00, dm2=0x0E00, dml=0x0F00 }; 

{bw=l, load=2, int_a=0, int_b=4}; 

{bw=l, mask_load=2 , irq_done=4}; 

{load=l, bw=2 , req=4, isack=8}; 


13.13 Opcodes 

The opcodes are exactly the same as the previous version. For con¬ 
venience, the following table shows the opcode organization. 

Table 13.40. Opcodes. 


0x00 

00. 

0x40 

010000 .. 

0x44 

010001 .. 

0x48 

010010 .. 

0x4C 

0100110. 

0x4E 

0100111. 

0x50 

010100 .. 

0x54 

010101 .. 

0x58 

010110 .. 

0x5C 

0101110. 

0x5E 

0101111. 


byte 0 


byte 1 


byte 2 


0x60 

01100 ... 

0x68 

01101 ... 

0x70 

OHIO. . . 

0x78 

01111 ... 

0x80 

10000000 

0x81 

10000001 

0x82 

1000001. 

0x84 

1000010. 

0x86 

1000011. 

0x88 

1000100. 


b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 


cp % % 

% 

% 

cp n % 

A, B, 1, J 

const16 

cp (%) % 

(U) 

A, B 



cp % (%) 

A, B 

(i. j) 



cp n (%) 

(i. j) 

const16 

cp (%) (%) 

(i. j) 



cp8 n % 

A, B, 1, J 

const8 


cp8 (%) % 

(U) 

A, B 



cp8 % (%) 

A, B 

(i. j) 



cp8 n (%) 

(i. j) 

const8 


cp8 (%) (%) 

(i. j) 






byte 0 




byte 1 

byte 2 

b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 




byte 3 


push % 


push8 % 


pop % 


pop8 % 


% 


% 


% 


% 


push n 


push8 n 


push (%) 


push8 (%) 


pop (%) 


pop8 (%) 


(I. J) 


(I. J) 


(I. J) 


(U) 


byte 3 


const16 


const8 



























































984 


Version "E" 


0x90 

0x98 

0x9A 

0x9C 

0x9E 

OxAO 

0xA2 

0xA4 

0xA6 

0xA8 

OxAA 


Ox AC 
OxAE 
OxBO 
0xB2 
0xB4 
0xB6 
OxB8 


OxBC 

OxBE 

OxCO 

0xC2 

0xC4 

0xC6 

OxC8 

OxCA 

OxCC 

OxCE 


OxDO 

0xD2 

0xD4 

0xD6 

OxD8 

OxDA 

OxDC 


byte 0 _ byte 1 byte 2 byte 3 



b7 

b6 

b5 

b4 

b3 

b2 

bl 

bO 


10010 ... 

jump %flag 0|1 #ref 

%flag 

TRUE 

#ref 

1001100. 

equal, not 

NOT 


1001101. 

and 

NOT 


1001110. 

or 

NOT 


1001111. 

xor 

NOT 


1010000. 

add, sub 

sub 


1010001. 

addc, subb 

sub 


1010010. 

Ish 

right 


1010011. 

ash 

right 


1010100. 

rote 

right 


1010101. 

rot 

right 



byte 0 byte 1 byte 2 byte 3 


1010110 . 
1010111 . 
1011000 . 
1011001 . 
1011010 . 
1011011 . 
101110 .. 


byte 0 byte 1 byte 2 byte 3 


1011110 . 

1011111 . 

1100000 . 

1100001 . 

1100010. 

1100011. 

1100100. 

1100101. 

1100110. 

1100111 . 


byte 0 byte 1 byte 2 byte 3 


1101000 . 

1101001. 

1101010. 

1101011 . 

1101100. 

1101101 . 

1101110 . 


b7 b6 b5 b4 b3 b2 bl 

bO 

add8s, sub8s 

sub 

add8cs, sub8bs 

sub 

Ish8ls, Ish8rs 

right 

ash8ls, ash8rs 

right 

rot8cls, rot8crs 

right 

rot8ls, rot8rs 

right 

casts 

sign 


b7 b6 b5 b4 b3 b2 bl 

bO 

equals, nots 

NOT 

ands 

NOT 

ors 

NOT 

xors 

NOT 

adds, subs 

sub 

addes, subbs 

sub 

Ishls, Ishrs 

right 

ashls, ashrs 

right 

rotcls, roters 

right 

rotls, rotrs 

right 


b7 | b6 | b5 | b4 | b3 | b2 | 

bl 

bO 

add8, sub8 

sub 

add8c, sub8b 

sub 

Ish8 

right 

ash8 

right 

rot8c 

right 

rot8 

right 

cast 

sign 

A, B 






Version "E" 


985 


OxDE 

OxDF 

OxEO 

OxEl 

0xE2 

0xE3 

0xE4 

0xE6 

OxE8 

OxEA 

OxEC 

OxEE 

OxFO 

OxFl 


0xF2 

0xF4 

0xF6 

OxF8 

OxFA 

OxFC 

OxFE 

OxFF 


11011110 

11011111 

11100000 

11100001 

11100010 

11100011 

1110010. 

1110011 . 

1110100. 

1110101 . 

mono. 

1110111 . 

11110000 

11110001 


1111001 . 

1111010 . 

1111011 . 

1111100 . 

1111101 . 

1111110 . 

11111110 

11111111 


byte 0 


b7 b6 b5 b4 b3 b2 bl bO 


call 


return 


byte 1 


byte 2 


byte 3 


#ref 


int 

int 


iret 



imrl 

mask 



ivtl 

#ref 


flag i 0|1 

set 



flag c 0|1 

set 



in n % 

A, B 

port 


in n (%) 

(U) 

port 

out % n 

A, B 

port 

out (%) n 

(i. j) 

port 

if ackjump 

port 

#ref 

if ack call 

port 

#ref 

byte 0 

byte 1 byte 2 byte 3 

b7 b6 b5 b4 b3 b2 bl 

bO 


cmpr, testr 

test 

cmpi, testi 

test 

cmps, tests 

test 

cmp8i, test8i 

test 

cmp8s, test8s 

test 

call (%) 

1, J 



jump 

#ref 


stop 




Table 13.41. Macrocode syntax: it is the same as the previous 
version. 


Macrocode syntax 

Description 

nop 

Not operate. 

cp %src, %dst 

Copy the src register content in¬ 
side the dst register. Allowed reg¬ 
isters are: I, J, A, B, BP, SP, C, 

FL . 

cp nl6, %dst 

Assign a 16-bit constant to a reg¬ 
ister. Allowed destination registers 
are: I, J, A, B. 

cp (%I %J), %A %B 

Assign to register A or B the 16- 
bit value contained in memory at 
the address already available from 
register / or /. 































































986 


Version "E" 


Macrocode syntax 

Description 

cp %A %B, (%I %J) 

Copy in memory the 16-bit value 
of register A or B, to the location 
represented by the register I or J. 

cp nl6, (%I 

%J) 

Assign in memory the 16-bit con¬ 
stant, to the location represented 
by the register I or J. 

cp (%I) 

Copy the 16-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register J. 

cp (%J) 

Copy the 16-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register I. 

cp8 w#, %dst 

Assign a 8-bit constant to a reg¬ 
ister. Allowed destination registers 
are: /, /, A, B. 

cp8 (%I %J) , %A %B 

Assign to register A or B the 8-bit 
value contained in memory at the 
address already available from reg¬ 
ister / or /. 

cp8 %A %B, (%I %J) 

Copy in memory the 8-bit value of 
register A or B, to the location rep¬ 
resented by the register I or J. 

cp8 (%I 

%J) 

Assign in memory the 8-bit con¬ 
stant, to the location represented 
by the register I or J. 

cp8 (%I) 

Copy the 8-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register J. 




Version "E" 


987 


Macrocode syntax 

Description 

cp8 (%J) 

Copy the 8-bit memory content at 
the address represented by register 
/, to the memory location repre¬ 
sented by the register /. 

push reg 

Push at the top of the stack the 16- 
bit value contained inside the reg¬ 
ister. 

pop reg 

Pop from the stack a 16-bit value 
that is then assigned to the register. 

push8 reg 

Push at the top of the stack the 8- 
bit value contained inside the reg¬ 
ister. 

pop8 reg 

Pop from the stack a 8-bit value 
that is then assigned to the register. 

push nl6 

Push at the top of the stack the 16- 
bit constant. 

push n8 

Push at the top of the stack the 8- 
bit constant. 

push (%I %J) 

Push at the top of the stack the 16- 
bit value contained in memory, at 
the location represented by register 
I or /. 

push (%I %J) 

Push at the top of the stack the 16- 
bit value contained in memory, at 
the location represented by register 
I or/. 

push8 (%I %J) 

Push at the top of the stack the 8- 
bit value contained in memory, at 
the location represented by register 
/ or/. 




988 


Version "E" 


Macrocode syntax 

Description 

pop (%I %J) 

Pop from the top of the stack a 
16-bit value that is then copied at 
the memory location represented 
by register I or J. 

pop8 (%I %J) 

Pop from the top of the stack a 

8-bit value that is then copied at 
the memory location represented 
by register I or J. 

jump %ref 

Jump to the address specified. 

jump %carry | %borrowf_. 

'■ :> | %zero | %negativep_> 

^ j %overflow, ^ 

^ 0 | 1, #ref 

Conditional jump. The first argu¬ 
ment is a pseudo-register that se¬ 
lects the flag; the second argu¬ 
ment means the value that the flag 
should have; the third argument is 
the address where the jump should 
go if the condition is met. 

equal 

C A , updating the flags status 

not 

C < — A , updating the flags status 
(one’s complement). 

and 

C A & B, updating the flags. 

nand 

C ~(A & B), updating the flags. 

or 

C <— A 1 B, updating the flags. 

nor 

C <— ~(A 1 B ), updating the flags. 




Version "E" 


989 


Macrocode syntax 

Description 

xor 

C <— A A B, updating the flags. 

nxor 

C ~(A A B ), updating the flags. 

add 

C A + B, updating the flags, 16- 
bit. 

sub 

C A - B, updating the flags, 16- 
bit. 

addc 

C A + B + carry, updating the 
flags, 16-bit. 

subb 

C 4 — A — B — borrow, updating the 
flags, 16-bit. 

lshl 

C A«l, updating the flags: 

logic shift left, 16-bit. 

lshr 

C A»l, updating the flags: 

logic shift right, 16-bit. 

ashl 

C A<«1, updating the flags: 

arithmetic shift left, 16-bit. 

ashr 

C A»>1, updating the flags: 

arithmetic shift right, 16-bit. 

rotcl 

C rotcl(A), updating the flags: 

rotation left with carry, 16-bit. 

rotcr 

C rotcr(A), updating the flags: 

rotation right with carry, 16-bit. 

rot 1 

C v- rotl(A), updating the flags: 
rotation left, 16-bit. 




990 


Version "E" 


Macrocode syntax 

Description 

rotr 

C <— rotr(A), updating the flags: 
rotation right, 16-bit. 

add8 

C A + B, updating the flags, 8- 
bit. 

sub8 

C A - B, updating the flags, 8- 
bit. 

add8c 

C A + B + carry, updating the 
flags, 8-bit. 

sub8b 

C i — A — B — borrow, updating the 
flags, 8-bit. 

lsh81 

C A«l, updating the flags: 

logic shift left, 8-bit. 

lsh8r 

C A»l, updating the flags: 

logic shift right, 8-bit. 

ash81 

C A<«1, updating the flags: 

arithmetic shift left, 8-bit. 

ash8r 

C A»>1, updating the flags: 

arithmetic shift right, 8-bit. 

rot8cl 

C rot8cl(A), updating the flags: 
rotation left with carry, 8-bit. 

rot8cr 

C rot8cr(A), updating the flags: 
rotation right with carry, 8-bit. 

rot 81 

C rot81(A), updating the flags: 
rotation left, 8-bit. 

rot 8r 

C rot8r(A), updating the flags: 
rotation right, 8-bit. 




Version "E" 


991 


Macrocode syntax 

Description 

cast 0 1 %A %B 

Adapt the register value to 8-bit, 
unsigned or signed, depending on 
the first argument. 

equals 

Read the 16-bit value on top of the 
stack and update the flags. 

not s 

Read the 16-bit value on top of the 
stack and replace it with the one’s 
complement, updating the flags. 

ands 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
AND of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

nands 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
NAND of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

ors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
OR of them, updating the flags, the 
registers A and B are overwritten. 

nors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
NOR of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 




992 


Version "E" 


Macrocode syntax 

Description 

xors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
XOR of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

nxors 

Pop two 16-bit values from the top 
of the stack and push the bitwise 
NXOR of them, updating the flags, 
the registers A and B are overwrit¬ 
ten. 

adds 

Pop two 16-bit values from the top 
of the stack and push the sum of 
them, updating the flags. To do the 
calculation, the registers A and B 
are overwritten. 

subs 

Pop a 16-bit values from the top 
of the stack and put it inside the 
register B ; then pop another 16-bit 
value and put inside the register A ; 
then calculate A-B updating the 
flags and push the result inside the 
stack again. 

addcs 

Pop two 16-bit values from the top 
of the stack and push the sum with 
carry of them, updating the flags. 
To do the calculation, the registers 
A and B are overwritten. 




Version "E" 


993 


Macrocode syntax 

Description 

subbs 

Pop a 16-bit values from the top 
of the stack and put it inside the 
register B\ then pop another 16- 
bit value and put inside the regis¬ 
ter A ; then calculate A -B -borrow 
updating the flags and push the re¬ 
sult inside the stack again. 

lshls 

Pop a 16-bit values from the top of 
the stack and push the logic shift 
left of it, updating the flags. 

lshrs 

Pop a 16-bit values from the top of 
the stack and push the logic shift 
right of it, updating the flags. 

ashls 

Pop a 16-bit values from the top of 
the stack and push the arithmetic 
shift left of it, updating the flags. 

ashrs 

Pop a 16-bit values from the top of 
the stack and push the arithmetic 
shift right of it, updating the flags. 

rotcls 

Pop a 16-bit values from the top of 
the stack and push the rotation left 
with carry of it, updating the flags. 

rotcrs 

Pop a 16-bit values from the top 
of the stack and push the rotation 
right with carry of it, updating the 
flags. 

rotls 

Pop a 16-bit values from the top of 
the stack and push the rotation left 
of it, updating the flags. 




994 


Version "E" 


Macrocode syntax 

Description 

rotrs 

Pop a 16-bit values from the top 
of the stack and push the rotation 
right of it, updating the flags. 

add8s 

Pop two 8-bit values from the top 
of the stack and push the sum of 
them, updating the flags. To do the 
calculation, the registers A and B 
are overwritten. 

sub8s 

Pop a 8-bit values from the top of 
the stack and put it inside the reg¬ 
ister B; then pop another 16-bit 
value and put inside the register A ; 
then calculate A-B updating the 
flags and push the result inside the 
stack again. 

add8cs 

Pop two 8-bit values from the top 
of the stack and push the sum with 
carry of them, updating the flags. 
To do the calculation, the registers 
A and B are overwritten. 

sub8bs 

Pop a 8-bit values from the top 
of the stack and put it inside the 
register B\ then pop another 16- 
bit value and put inside the regis¬ 
ter A ; then calculate A -B -borrow 
updating the flags and push the re¬ 
sult inside the stack again. 

lsh81s 

Pop a 8-bit values from the top of 
the stack and push the logic shift 
left of it, updating the flags. 




Version "E" 


995 


Macrocode syntax 

Description 

lsh8rs 

Pop a 8-bit values from the top of 
the stack and push the logic shift 
right of it, updating the flags. 

ash81s 

Pop a 8-bit values from the top of 
the stack and push the arithmetic 
shift left of it, updating the flags. 

ash8rs 

Pop a 8-bit values from the top of 
the stack and push the arithmetic 
shift right of it, updating the flags. 

rotc81s 

Pop a 8-bit values from the top of 
the stack and push the rotation left 
with carry of it, updating the flags. 

rotc8rs 

Pop a 8-bit values from the top 
of the stack and push the rotation 
right with carry of it, updating the 
flags. 

rot81s 

Pop a 8-bit values from the top of 
the stack and push the rotation left 
of it, updating the flags. 

rot8rs 

Pop a 8-bit values from the top 
of the stack and push the rotation 
right of it, updating the flags. 

casts 0 1 

Pop a 16-bit value from the top 
of the stack and push the same 
value, adapted to 8-bit, unsigned 
or signed, depending on the argu¬ 
ment. 

call #ref 

Call the procedure that starts at the 
argument reference: the registers 
FL and PC are pushed inside the 
stack. 




996 


Version "E" 


Macrocode syntax 

Description 

call (%I 

%J) 

Call the procedure that starts at the 
position contained inside register I 
or J: the registers FL and PC are 
pushed inside the stack. 

return 

Return from a previous call: the 
registers PC and FL are retrieved 
from the stack. 

int n8 

Software interrupt call: the regis¬ 
ters FL and PC are pushed inside 
the stack. 

iret 

Return from an interrupt: the regis¬ 
ters PC and FL are retrieved from 
the stack. 

imrl n8 

Load the IMR: interrupt mask reg¬ 
ister. 

ivtl #ref 

Load the IVT: interrupt vector ta¬ 
ble. The argument is the interrupt 
vector table start address in mem¬ 
ory. 

flag_i 0 

1 

Reset or set the flag that allows the 
hardware interrupts. 

flag_c 0 

1 

Reset or set the carry (borrow) 
flag. 

in n8, %A %B 

Read from the I/O address spec¬ 
ified, a byte that is copied inside 
register A or/?. 

in n8, (%I %J) 

Read from the I/O address speci¬ 
fied, a byte that is copied in mem¬ 
ory, at the address specified by reg¬ 
ister / or /. 




Version "E" 


997 


Macrocode syntax 

Description 

out %A %B, ffS 

Write to the I/O address specified, 
a byte that is read from register A 
or B. 

out (%I %J) , ffS 

Write to the I/O address specified, 
a byte that is read from memory, at 
the address specified by register I 
or J. 

ifack_jump w#, #ref 

If the I/O port gives an acknoledge 
report, then jump to the specified 
address. 

ifack_call n8, #ref 

If the I/O port gives an acknoledge 
report, then call the specified pro¬ 
cedure. 

cmpr 

Calculate A-B , updating the flags, 
without modifying the accumula¬ 
tor. 

testr 

Calculate A&B (bitwise AND), 
updating the flags, without modi¬ 
fying the accumulator. 

cmpi 

Load A with the value contained in 
memory at the address represented 
by the register /; load B with the 
value contained in memory at the 
address represented by the regis¬ 
ter J; then calculate A-B , updat¬ 
ing the flags, without modifying 
the accumulator. 




998 


Version "E" 


Macrocode syntax 

Description 

testi 

Load A with the value contained in 
memory at the address represented 
by the register /; load B with the 
value contained in memory at the 
address represented by the regis¬ 
ter J; then calculate A &B (bitwise 
AND), updating the flags, without 
modifying the accumulator. 

cmps 

Read from the top of the stack a 
16-bit value and put it inside the 
register B ; read from the stack, just 
under the previous value, a 16-bit 
value and put it inside the regis¬ 
ter A; then calculate A-B , updat¬ 
ing the flags, without modifying 
the accumulator. 

tests 

Read from the top of the stack a 
16-bit value and put it inside the 
register B ; read from the stack, just 
under the previous value, a 16-bit 
value and put it inside the regis¬ 
ter A; then calculate A&B , updat¬ 
ing the flags, without modifying 
the accumulator. 

cmp8r 

Calculate 8-bit A-B, updating the 
flags, without modifying the accu¬ 
mulator. 

test8r 

Calculate 8-bit A&B (bitwise 
AND), updating the flags, without 
modifying the accumulator. 




Version "E" 


999 


Macrocode syntax 

Description 

cmp8i 

Load 8-bit inside A with the value 
contained in memory at the ad¬ 
dress represented by the register /; 
load 8-bit inside B with the value 
contained in memory at the ad¬ 
dress represented by the register J ; 
then calculate A-B, updating the 
flags, without modifying the accu¬ 
mulator. 

test8i 

Load 8-bit inside A with the value 
contained in memory at the ad¬ 
dress represented by the register /; 
load 8-bit inside B with the value 
contained in memory at the ad¬ 
dress represented by the register J; 
then calculate A&B , updating the 
flags, without modifying the accu¬ 
mulator. 

cmp8s 

Read from the top of the stack a 8- 
bit value and put it inside the reg¬ 
ister B; read from the stack, just 
under the previous value, a 8-bit 
value and put it inside the regis¬ 
ter A; then calculate A-B, updat¬ 
ing the flags, without modifying 
the accumulator. 




1000 


Version "E" 


Macrocode syntax 

Description 

test8s 

Read from the top of the stack a 8- 
bit value and put it inside the reg¬ 
ister B ; read from the stack, just 
under the previous value, a 8-bit 
value and put it inside the regis¬ 
ter A; then calculate A&B, updat¬ 
ing the flags, without modifying 
the accumulator. 

stop 

Stop the system. 


Listing 13.42. Registers, flags and opcodes encoded for TKGate. 
This encoding is the same as the previous version, because the 
opcodes do not change. 


registers 1=0, J=l, A=2, B=3, BP=4, SP=5, C=6, FL=7; 


registers carry=0, borrow=0, zero=l, negative=2, overflow=3; 


// - 

op nop { 

map nop: 0x00; // not operate 

operands { - = { +0=0x00; }; }; 

}; 

// 


op cp { 


// 




00 . 

= 

cp 

%, % 

map 

nop: 

0x00; 

// 

00000000 

= 

cp 

%J, %I 

map 

c P_i_j : 

0x01; 

// 

00000001 

= 

cp 

%I, %J 

map 

cp_i_a: 

0x02; 

// 

00000010 

= 

cp 

%I, %A 

map 

cp_i_b: 

0x03; 

// 

00000011 

= 

cp 

%I, %B 

map 

cp_i_bp: 

0x04; 

// 

00000100 

= 

cp 

%I, %BP 

map 

cp_i_sp: 

0x05; 

// 

00000101 

= 

cp 

%I, %SP 

map 

cp_i_c: 

0x06; 

// 

00000110 

= 

cp 

%I, %C 

map 

cp_i_f1: 

0x07; 

// 

00000111 

= 

cp 

%I,%FL 












Version "E" 


1001 


map 

o 

1 

LJ- 

1 

H- 

0x08; 

// 

OOOOIOOO 

= 

cp 

%J, %I 


map 

nop : 

0x09; 

// 

OOOOlOOl 

= 

cp 

%J, %J = 

nop 

map 

cp_j_a : 

OxOA; 

// 

OOOOIOIO 

= 

cp 

%J, %A 


map 

cp_j_b : 

OxOB; 

// 

OOOOlOll 

= 

cp 

%J, %B 


map 

cp_j_bp 

0 x 0 C; 

// 

OOOOllOO 

= 

cp 

%J, %BP 


map 

cp_j_sp 

OxOD; 

// 

OOOOllOl 

= 

cp 

%J, %SP 


map 

cp_j_c : 

OxOE; 

// 

OOOOlllO 

= 

cp 

%J, %c 


map 

cp_j_fl 

OxOF; 

// 

OOOOllll 

= 

cp 

%J, %FL 


map 

cp_a_i : 

0x10; 

// 

OOOIOOOO 

= 

cp 

%A, %I 


map 

cp_a_j : 

0x11; 

// 

OOOlOOOl 

= 

cp 

%A, %J 


map 

nop : 

0x12; 

// 

OOOIOOIO 

= 

cp 

%A, %A = 

nop 

map 

cp_a_b : 

0x13; 

// 

OOOlOOll 

= 

cp 

%A, %B 


map 

cp_a_bp 

0x14; 

// 

OOOIOIOO 

= 

cp 

%A, %BP 


map 

cp_a_sp 

0x15; 

// 

OOOIOIOI 

= 

cp 

%A, %SP 


map 

cp_a_c: 

0x16; 

// 

00010110 

= 

cp 

%A, %C 


map 

cp_a_f1 

0x17; 

// 

OOOlOlll 

= 

cp 

%A, %FL 


map 

cp_b_i : 

0x18; 

// 

OOOllOOO 

= 

cp 

%B, %I 


map 

cp_b_j : 

0x19; 

// 

OOOllOOl 

= 

cp 

%B, %J 


map 

cp_b_a : 

OxlA; 

// 

OOOllOlO 

= 

cp 

%B, %A 


map 

nop : 

OxlB; 

// 

OOOllOll 

= 

cp 

%B, %B = 

nop 

map 

cp_b_bp : 

: 0 x 1 C; 

// 

OOOlllOO 

= 

cp 

%B, %BP 


map 

cp_b_sp : 

: OxlD; 

// 

OOOlllOl 

= 

cp 

%B, %SP 


map 

cp_b_c : 

OxlE; 

// 

OOOllllO 

= 

cp 

%B, %C 


map 

cp_b_f1 

OxlF; 

// 

OOOlllll 

= 

cp 

%B, %FL 


map 

cp_bp_i 

0x20; 

// 

OOIOOOOO 

= 

cp 

%BP, %I 


map 

cp_bp_j 

0x21; 

// 

OOlOOOOl 

= 

cp 

%BP,%J 


map 

cp_bp_a 

0x22; 

// 

OOIOOOIO 

= 

cp 

%BP, %A 


map 

cp_bp_b 

0x2 3; 

// 

OOlOOOll 

= 

cp 

%BP, %B 


map 

nop: 

0x2 4; 

// 

OOIOOIOO 

= 

cp 

%BP,%BP 

= nop 

map 

cp_bp_sp: 0x25; 

// 

OOIOOIOI 

= 

cp 

%BP, %SP 


map 

cp_bp_c: 

: 0x26; 

// 

OOlOOllO 

= 

cp 

%BP, %C 

= nop 

map 

cp_bp_fl: 0x27; 

// 

OOlOOlll 

= 

cp 

%BP, %FL 


map 

cp_sp_i 

0x28; 

// 

OOIOIOOO 

= 

cp 

%SP, %I 


map 

cp_sp_j 

0x2 9; 

// 

00101001 

= 

cp 

%SP, %J 


map 

cp_sp_a 

0x2A; 

// 

OOIOIOIO 

= 

cp 

%SP, %A 


map 

cp_sp_b 

0x2B; 

// 

00101011 

= 

cp 

%SP, %B 







1002 


Version "E" 


map 

cp_sp_bp : 

0x2C; 

// 

00101100 

= 

cp 

%SP,%BP 

map 

nop: 


0x2D; 

// 

00101101 

= 

cp 

%SP, %SP = nop 

map 

cp_sp_c 


0x2E; 

// 

00101110 

= 

cp 

%SP, %C 

map 

cp_sp_fl: 

0x2F; 

// 

00101111 

= 

cp 

%SP, %FL 

map 

cp_c_i : 


0x30; 

// 

00110000 

= 

cp 

%C, %I 

map 

cp_c_j: 


0x31; 

// 

00110001 

= 

cp 

%C, %J 

map 

cp_c_a: 


0x32; 

// 

00110010 

= 

cp 

%C, %A 

map 

cp_c_b : 


0x33 ; 

// 

00110011 

= 

cp 

%C, %B 

map 

cp_c_bp 


0x34 ; 

// 

00110100 

= 

cp 

%C, %BP 

map 

cp_c_sp 


0x35 ; 

// 

00110101 

= 

cp 

%C, %SP 

map 

nop : 


0x3 6; 

// 

00110110 

= 

cp 

%C, %C = nop 

map 

cp_c_f1 


0x37; 

// 

00110111 

= 

cp 

%C, %FL 

map 

cp_fl_i 


0x38; 

// 

00111000 

= 

cp 

%FL, %I 

map 

cp_fl_j 


0x3 9; 

// 

00111001 

= 

cp 

%FL, %J 

map 

cp_fl_a 


0x3A; 

// 

00111010 

= 

cp 

%FL,%A 

map 

cp_fl_b 


0x3B; 

// 

00111011 

= 

cp 

%FL, %B 

map 

cp_fl_bp: 

0 x 3 C; 

// 

00111100 

= 

cp 

%FL,%BP 

map 

cp_fl_sp : 

0x3D; 

// 

00111101 

= 

cp 

%FL, %SP 

map 

cp_fl_c : 


0x3E; 

// 

00111110 

= 

cp 

%FL, %C 

map 

nop : 


0x3F; 

// 

00111111 

= 

cp 

%FL,%FL = nop 

// 





010000.. 

= 

cp 

#,% 

map 

cp_num_i : 

0x4 0; 

// 

01000000 

= 

cp 

#, %J 

map 

cp_num_j : 

0x41; 

// 

01000001 

= 

cp 

#, %J 

map 

cp_num_a : 

0x42 ; 

// 

01000010 

= 

cp 

#,%A 

map 

cp_num_b : 

0x4 3; 

// 

01000011 

= 

cp 

#, %B 

// 





010001.. 

= 

cp 

(%),% 

map 

cp_mi_a 


0x4 4; 

// 

01000100 

= 

cp 

(%I) , %A 

map 

cp_mi_b 


0x4 5; 

// 

01000101 

= 

cp 

(%I) , %B 

map 

cp_mj_a 


0x46; 

// 

01000110 

= 

cp 

(%J) , %A 

map 

cp_mj_b 


0x4 7; 

// 

01000111 

= 

cp 

(%J) , %B 

// 





010010.. 

= 

cp 

%, %I 

map 

cp_a_mi: 


0x4 8; 

// 

01001000 

= 

cp 

%A, (%I) 

map 

cp_a_mj: 


0x4 9; 

// 

01001001 

= 

cp 

%A, (%J) 

map 

cp_b_mi: 


0x4A; 

// 

01001010 

= 

cp 

%B, (%I) 

map 

cp_b_mj: 


0x4B; 

// 

01001011 

= 

cp 

%B, (%J) 

// 





0100110. 

= 

cp 

#, (%) 








Version "E" 


1003 


map 

cp_num_mi: 

0x4C; 

// 

01001100 

= 

op i 

(%I) 

map 

cp_num_mj: 

0x4D; 

// 

01001101 

= 

cp , 

(%J) 

// 




0100111. 

= 

op 

(%) 

map 

cp_mi_mj: 

0x4E; 

// 

01001110 

= 

op 

(%I) 

map 

cp_mj_mi: 

0 x 4 F; 

// 

01001111 

= 

op 

(%J) 

// 








operands { 







%1 

r %2 = { 

+0=0x00; 

+0[5:3]=%1; 

+0[2:0]=%2; }; 

#1 

,%2 = { 

+0=0x40; 

+0[1:0]=%2; 

+1 

=#1 [7:0]; +2=#1[15:8]; }; 

(% 

1) / %2 = { 

+0=0x44; 

+0[1:1]=%1; 

+0[0:0]=%2; }; 

%1 

, (%2) = { 

+0=0x48; 

+0[1:1]=%1; 

+0[0:0]=%2; }; 

#1 

, (%2) = { 

+0=0x4C; 

+0[0:0]=%2; 

+i 

=#1 [7:0]; +2=#1[15:8]; }; 

<% 

}; 

1) = ( 

+0=0x4E; 

+0[0:0]=%1; 

}; 



o 

00 

{ 







// 




010100. . 

= 

cp8 

#,% 

map 

cp8_num_i: 

0x50; 

// 

01010000 

= 

cp8 

#, %I 

map 

cp8_num_j: 

0x51; 

// 

01010001 

= 

cp8 

#, %J 

map 

cp8_num_a: 

0x52; 

// 

01010010 

= 

cp8 

#, %A 

map 

cp8_num_b: 

0x53; 

// 

01010011 


cp8 

#, %B 

// 




010101. . 

= 

cp8 

(%),% 

map 

cp8_mi_a: 

0x54; 

// 

01010100 


cp8 

(%I ), %A 

map 

cp8_mi_b: 

0x55; 

// 

01010101 

= 

cp8 

(%I ), %B 

map 

cp8_mj_a: 

0x5 6; 

// 

01010110 


cp8 

(%J) , %A 

map 

cp8_mj_b: 

0x57; 

// 

01010111 

= 

cp8 

(%J) , %B 

// 




010110.. 

= 

cp8 

%, (%) 

map 

cp8_a_mi: 

0x58; 

// 

01011000 

= 

cp8 

%A, (%I) 

map 

cp8_a_mj: 

0x5 9; 

// 

01011001 

= 

cp8 

%A, (%J) 

map 

cp8_b_mi: 

0x5A; 

// 

01011010 

= 

cp8 

%B, (%I) 

map 

cp8_b_mj : 

0x5B; 

// 

01011011 

= 

cp8 

%B, (%J) 

// 




0101110. 


cp8 

#, (%) 

map 

cp8_num_mi 

. : 0x5C; 

// 

01011100 

= 

cp8 

#, (%I) 

map 

cp8_num_mj 

: 0x5D; 

// 

01011101 


cp8 

#, ( %J ) 

// 




0101111. 

= 

cp8 

(%) 

map 

cp8_mi_mj : 

0x5E; 

// 

01011110 


cp8 

(%I) 








1004 


Version "E" 


map cp8_mj_mi: 

0x5F; 

// 01011111 = cp8 (%J) 


// 

operands { 

#1,%2 = { 

+0=0x50; 

+0[1:0]=%2; +1=#1[7:0]; 

}; 

(%1),%2 = { 

+0=0x54; 

+0[1:1]=%1; +0[0:0]=%2; 

}; 

%1,(%2) = { 

+0=0x58; 

+0[1:1]=%1; +0[0:0]=%2; 

}; 

#1,(%2) = { 

+0=0x5C; 

+0[0:0]=%2; +1=#1[7:0]; 

}; 

(%1) = { 

+0=0x5E; 

+0[0:0]=%1; }; 


}; 

}; 

// 

op push { 

// 

map push_i: 

0x60; 

01100... = push % 

// 01100000 = push %I 


map push_j: 

0x61; 

// 01100001 = push %J 


map push_a: 

0x62; 

// 01100010 = push %A 


map push_b: 

0x63; 

// 01100011 = push %B 


map push_bp: 

0x64; 

// 01100100 = push %BP 


map push_sp: 

0x65; 

// 01100101 = push %SP 


map push_c: 

0x66; 

// 01100110 = push %C 


map push_fl: 

0x67; 

// 01100111 = push %FL 


// 

map push_num: 

0x80; 

// 10000000 = push # 


// 

map push_mi: 

0x82; 

// 10000010 = push (%I) 


map push_mj: 

0x83; 

// 10000011 = push (%J) 


// 

operands { 

%1 = { +0= 

0x60; +0[2:0]=%1; }; 


#1 = { +0= 

0x80; +1= 

■41 [7:0]; +2=#1 [15:8] ; }; 


(%1) = { + 0 = 

0x82; +0[0:0]=%1; }; 


}; 

}; 

op pop { 

// 

map pop_i: 

0x7 0; 

OHIO. . . = pop % 

// 01110000 = pop %I 






Version "E" 


1005 


map 

pop_j: 

0x71; 

// 

01110001 


pop %J 

map 

pop_a: 

0x72; 

// 

01110010 

= 

pop %A 

map 

pop_b: 

0x7 3; 

// 

01110011 

= 

pop %B 

map 

pop_bp: 

0x7 4; 

// 

01110100 

= 

pop %BP 

map 

pop_sp: 

0x7 5; 

// 

01110101 

= 

pop %SP 

map 

pop_c: 

0x7 6; 

// 

01110110 

= 

pop %C 

map 

pop_f1: 

0x7 7; 

// 

01110111 

= 

pop %FL 

// 




1000011. 


pop (%) 

map 

pop_mi: 

0x86; 

// 

10000110 

= 

pop (%I) 

map 

pop_mj: 

0x87; 

// 

10000111 

= 

pop (%J) 

// 








operands { 







o 

"o 

1 = { +0= 

0x70; +0 [2:0 

]=%1; }; 




< 

}; 

%1) = { +0= 

0x86; +0[0:0 

]=%i; }; 




}; 

// 








op push8 { 







// 




01101... 

= 

push 8 

% 

map 

push8_i: 

0x68; 

// 

01101000 

= 

push 8 

%I 

map 

push8_j: 

0x69; 

// 

01101001 


push 8 

%J 

map 

push8_a: 

0x6A; 

// 

01101010 

= 

push 8 

%A 

map 

push8_b: 

0x6B; 

// 

01101011 


push 8 

%B 

map 

push8_bp: 

0x6C; 

// 

01101100 

= 

push 8 

%BP 

map 

push8_sp: 

0x6D; 

// 

01101101 

= 

push 8 

%SP 

map 

push8_c: 

0x6E; 

// 

01101110 

= 

push 8 

%C 

map 

push8_f1: 

0x6F; 

// 

01101111 

= 

push 8 

%FL 

// 








map 

push8_num: 

0x81; 

// 

10000001 

= 

push 8 

# 

// 




1000010. 

= 

push 8 

(%I) 

map 

push8_mi: 

0x84; 

// 

10000100 

= 

push 8 

(%I) 

map 

push8_mj: 

0x85; 

// 

10000101 


push 8 

(%J) 

// 








operands { 







o 

"o 

1 = { +0= 

0x68; +0[2:0 

]=%1; }; 




#1 = { +0= 

0x81; +1[7:0 

]=#i; }; 









1006 


Version "E" 


(%1) = { +0 

= 0x81; +0 [ 0:0 

]=%i; }; 





}; 








}; 








op pop8 { 








// 



01111.. . 

= 

pop 8 

% 


map pop8_i: 

0x7 8; 

// 

01111000 

= 

pop 8 

%I 


map pop8_j: 

0x7 9; 

// 

01111001 

= 

pop 8 

%J 


map pop8_a: 

0x7A; 

// 

01111010 

= 

pop 8 

%A 


map pop8_b: 

0x7B; 

// 

01111011 

= 

pop 8 

%B 


map pop8_bp: 

0x7C; 

// 

01111100 

= 

pop 8 

%BP 


map pop8_sp: 

0x7D; 

// 

01111101 

= 

pop 8 

%SP 


map pop8_c: 

0x7E; 

// 

01111110 

= 

pop 8 

%C 


map pop8_fl: 

0x7F; 

// 

01111111 

= 

pop 8 

%FL 


// 


// 

1000100. 

= 

pop 8 

(%) 


map pop8_mi: 

0x88; 

// 

10001000 

= 

pop 8 

(%I) 


map pop8_mj: 

0x89; 

// 

10001001 

= 

pop 8 

(%J) 


// 








operands { 








%1 = { +0 

=0x78; +0 [2:0 

]=%i; }; 





(%1) = { +0 

}; 

= 0x88; +0 [0:0 

]=%i; }; 





}; 

// 








op jump { 








map jump_nc: 

0x90; 

// 

10010000 

= 

jump 

%carry 0 # 


map j ump_c: 

0x91; 

// 

10010001 

= 

jump 

%carry 1 # 


map jump_nz: 

0x92; 

// 

10010010 

= 

jump 

%zero 0 # 


map jump_z: 

0x93; 

// 

10010011 

= 

jump 

%zero 1 # 


map jump_nn: 

0x94; 

// 

10010100 

= 

jump 

%negative 0 

# 

map j ump_n: 

0x95; 

// 

10010101 

= 

jump 

%negative 1 

# 

map jump_no: 

0x96; 

// 

10010110 

= 

jump 

%overflow 0 

# 

map j ump_o: 

0x97; 

// 

10010111 

= 

jump 

%overflow 1 

# 

// 








map jump: 

OxFE; 

// 

11111110 

= 

jump 

# 


// 








operands { 













Version "E" 


1007 


%1,#2,#3 
#1 

}; 

}; 

// 

op equal { 
map equal: 
operands { - 

}; 

op not { 
map not: 
operands { - 

}-• 

// 

op and { 
map and: 
operands { - 

}; 

op nand { 
map nand: 
operands { - 

}; 

// 

op or { 
map or: 
operands { - 

}; 

op nor { 
map nor: 
operands { - 

}; 

// 

op xor { 
map xor: 
operands { - 


= { +0=0x90; +0[2:1]=%1; +0[0:0]=#2; 

+ 1=#3 [7:0]; +2=#3[15:8]; }; 

= { +0=0xFE; +1=#1[7:0]; +2=#1[15:8]; 


0x98; // 10011000 = equal 

= { +0=0x98; }; }; 

0x99; // 10011001 = not 

= { +0=0x99; }; }; 


0x9A; // 10011010 = and 

= { +0=0x9A; }; }; 

0x9B; // 10011011 = nand 

= { +0=0x9B; }; }; 


0x9C; // 10011100 = or 

= { +0=0x9C; }; }; 

0x9D; // 10011101 = nor 

= { +0=0x9D; }; }; 


0x9E; // 10011110 = xor 

= { +O=0x9E; }; }; 


}; 



1008 


Version "E" 


I; 

op nxor { 
map nxor: 
operands { 

}; 

// 

op add { 
map add: 
operands { 

}; 

op sub { 
map sub: 
operands { 

}-• 

// 

op addc { 
map addc: 
operands { 

}; 

op subb { 
map subb: 
operands { 

}; 

// 

op lshl { 
map lshl: 
operands { 

}; 

op lshr { 
map lshr: 
operands { 

}; 

// 

op ashl { 
map ashl: 
operands { 


0x9F; // 10011111 = nxor 

{ +0=0x9F; }; }; 


OxAO; // 10100000 = add 

{ +0=0xA0; }; }; 


OxAl; // 10100001 = sub 

{ +0=0xAl; }; }; 


0xA2; // 10100010 = addc 

{ +0=0xA2; }; }; 


0xA3; // 10100011 = subb 

{ +0=0xA3; }; }; 


0xA4; // 10100100 = lshl 

{ +0=0xA4; }; }; 


0xA5; // 10100101 = lshr 

{ +0=0xA5; }; }; 


0xA6; // 10100110 = ashl 

{ +0=0xA6; }; }; 



Version "E" 


1009 


I; 

op ashr { 
map ashr: 
operands { 

}; 

// 

op rotcl { 
map rotcl: 
operands { 

}; 

op rotcr { 
map rotcr: 
operands { 

}-• 

// 

op rotl { 
map rotl: 
operands { 

}; 

op rotr { 
map rotr: 
operands { 

}; 

// 

op add8 { 
map add8: 
operands { 

}; 

op sub8 { 
map sub8: 
operands { 

}; 

// 

op add8c { 
map add8c: 
operands { 


0xA7; // 10100111 = ashr 

{ +0=0xA7; }; }; 


0xA8; // 10101000 = rotcl 

{ +0=0xA8; }; }; 


0xA9; // 10101001 = rotcr 

{ +0=0xA9; }; }; 


OxAA; // 10101010 = rotl 

{ +0=0xAA; }; }; 


OxAB; // 10101011 = rotr 

{ +0=0xAB; }; }; 


OxAC; // 10101100 = addS 

{ +0=0xAC; }; }; 


OxAD; // 10101101 = sub8 

{ +0=0xAD; }; }; 


OxAE; // 10101110 = addc8 

{ +0 = 0 xAE; }; }; 



1010 


Version "E" 


}; 

op sub8b { 
map sub8b: 
operands { - 

}; 

// 

op lsh81 { 
map lsh81: 
operands { - 

}; 

op lsh8r { 
map lsh8r: 
operands { - 

}-• 

// 

op ash81 { 
map ash81: 
operands { - 

}; 

op ash8r { 
map ash8r: 
operands { - 

}; 

// 

op rot8cl { 
map rot8cl: 
operands { - 

}; 

op rot8cr { 
map rot8cr: 
operands { - 

}; 

// 

op rot81 { 
map rot81: 
operands { - 


OxAF; // 10101111 = subb8 

{ +0=0xAF; }; }; 


OxBO; // 10110000 = lshl81 

{ +0=0xB0; }; }; 


OxBl; // 10110001 = lshl8r 

{ +0=0xBl; }; }; 


0xB2; // 10110010 = ashl81 

{ +0=0xB2; }; }; 


0xB3; // 10110011 = ashl8r 

{ +0=0xB3; }; }; 


0xB4; // 10110100 = rotc81 

{ +0=0xB4; }; }; 


0xB5; // 10110101 = rotc8r 

{ +0=0xB5; }; }; 


0xB6; // 10110110 = rot81 

{ +0=0xB6; }; }; 



Version "E" 


1011 


}; 

op rot8r { 


map rot8r: 

0xB7; 

// 

10110111 

operands { - = 

{ +0=0xB7; 

}; I; 

}; 




// 




op cast { 




// 


// 

101110.. 

map cast_uns_a 

: 0xB8; 

// 

10111000 

map cast_uns_b 

: 0xB9; 

// 

10111001 

map cast_sig_a 

: OxBA; 

// 

10111010 

map cast_sig_b 

: OxBB; 

// 

10111011 

operands { 




#1,%2 = {+0=( 

DxB8; +0[1:1 

]=#1; +0[ 


}; 

}; 

// 

op equals { 

map equals: OxBC; // 10111100 

operands { - = { +0=0xBC; }; }; 

}; 

op nots { 

map nots: OxBD; // 10111101 

operands { - = { +0=0xBD; }; }; 

}; 

// 

op ands { 

map ands: OxBE; // 10111110 

operands { - = { +0=0xBE; }; }; 

}; 

op nands { 

map nands: OxBF; // 10111111 

operands { - = { +0=0xBF; }; }; 

}; 

// 

op ors { 


rot8r 


cast <sig>, % 
cast 0, %A 
cast 0,%B 
cast 1, %A 
cast 1,%B 

: 0 ]=% 2 ; }; 


stack <= %A 


stack <= NOT %A 


stack <= %A AND %B 


stack <= %A NAND %B 




1012 


Version "E" 


map ors: 
operands { 

}; 

op nors { 
map nors: 
operands { 

}; 

// 

op xors { 
map xors: 
operands { 

}; 

op nxors { 
map nxors: 
operands { 

}; 

// 

op adds { 
map adds: 
operands { 

}; 

op subs { 
map subs: 
operands { 

}; 

// 

op addcs { 
map addcs: 
operands { 

}; 

op subbs { 
map subbs: 
operands { 

}; 

// 

op lshls { 


OxCO; // 11000000 = stack <= %A OR %B 

{ +0=0xC0; }; }; 


OxCl; // 11000001 = stack <= %A NOR %B 

{ +0=0xCl; }; }; 


0xC2; // 11000010 = stack <= %A XOR %B 

{ +0=0xC2; }; }; 


0xC3; // 11000011 = stack <= %A NXOR %B 

{ +0=0xC3; }; }; 


0xC4; // 11000100 = stack <= %A + %B 

{ +0=0xC4; }; }; 


0xC5; // 11000101 = stack <= %A - %B 

{ +0=0xC5; }; }; 


0xC6; // 11000110 = stack <= %A + %B + %carry 

{ +0=0xC6; }; }; 


0xC7; // 11000111 = stack <= %A — %B — %carry 

{ +0=0xC7; }; }; 



Version "E" 


1013 


map lshls: 
operands { - 

}; 

op lshrs { 
map lshrs: 
operands { - 

}; 

// 

op ashls { 
map ashls: 
operands { - 

}; 

op ashrs { 
map ashrs: 
operands { - 

}; 

// 

op rotcls { 
map rotcls: 
operands { - 

}; 

op rotcrs { 
map rotcrs: 
operands { - 

}; 

// 

op rotls { 
map rotls: 
operands { - 

}; 

op rotrs { 
map rotrs: 
operands { - 

}; 

// 

op add8s { 


0xC8; // 11001000 = stack <= lshl 

{ +0=0xC8; }; }; 


0xC9; // 11001001 = stack <= lshr 

{ +0=0xC9; }; }; 


OxCA; // 11001010 = stack <= ashl 

{ +0=0xCA; }; }; 


OxCB; // 11001011 = stack <= ashr 

{ +0=0xCB; }; }; 


OxCC; // 11001100 = stack <= rotcl 

{ +0=0xCC; }; }; 


OxCD; // 11001101 = stack <= rotcr 

{ +0=0xCD; }; }; 


OxCE; // 11001110 = stack <= rotl 

{ +0=0xCE; }; }; 


OxCF; // 11001111 = stack <= rotr 

{ +0=0xCF; }; }; 



1014 


Version "E" 


map add8s: 
operands { - 

}; 

op sub8s { 
map sub8s: 
operands { - 

}; 

// 

op add8cs { 
map add8cs: 
operands { - 

}; 

op sub8bs { 
map sub8bs: 
operands { - 

}; 

// 

op lsh81s { 
map lsh81s: 
operands { - 

}; 

op lsh8rs { 
map lsh8rs: 
operands { - 

}; 

// 

op ash81s { 
map ash81s: 
operands { - 

}; 

op ash8rs { 
map ash8rs: 
operands { - 

}; 

// 

op rot8cls { 


OxDO; // 11010000 = stack8 <= + 

{ +0=0xD0; }; }; 


OxDl; // 11010001 = stack8 <= - 

{ +0=0xDl; }; }; 


0xD2; // 11010010 = stack8 <= + + %carry 

{ +0=0xD2; }; }; 


0xD3; // 11010011 = stack8 <= - - %carry 

{ +0=0xD3; }; }; 


0xD4; // 11010100 = stack8 <= lsh8r 

{ +0=0xD4; }; }; 


0xD5; // 11010101 = stack8 <= lsh8r 

{ +0=0xD5; }; }; 


0xD6; // 11010110 = stack8 <= ash81 

{ +0=0xD6; }; }; 


0xD7; // 11010111 = stack8 <= ash8r 

{ +0=0xD7; }; }; 



Version "E" 


1015 


map rot8cls: 0xD8; // 11011000 = stack8 <= rot8cl 

operands { - = { +0=0xD8; }; }; 

}; 

op rot8crs { 

map rot8crs: 0xD9; // 11011001 = stack8 <= rot8cr 

operands { - = { +0=0xD9; }; }; 

}; 

// 

op rot81s { 

map rot81s: OxDA; // 11011010 = stack8 <= rot81 

operands { - = { +0=0xDA; }; }; 

}; 

op rot8rs { 

map rot8rs: OxDB; // 11011011 = stack8 <= rot8r 

operands { - = { +0=0xDB; }; }; 

}; 

// 

op casts { 


// 


// 1101110. = casts 

<sig> 

map casts_uns: 

OxDC; 

// 11011100 = casts 

0 

map casts_sig: 
operands { 

OxDD; 

// 11011101 = casts 

1 

#1 = {+0=0xDC; 

+ 0 [0 

: 0] = # 1; }; 



}; 

}; 

// 

op call { 

map call: OxDE; // 11011110 = call # 

map call_i: OxFC; // 11111100 = call (%I) 

map call_j: OxFD; // 11111101 = call (%J) 

operands { 

#1 = { +0=0xDE; +1=#1[7:0]; +2=#1[15:8]; }; 

(%1) = { +0=0xFC; +0[0:0]=%1; }; 

}; 

}; 

op return { 



1016 


Version "E" 


map return: OxDF; // 11011111 = return 

operands { - = { +0=0xDF; }; }; 

}; 

// 

op int { 

map int: OxEO; // 11100000 = int <n> 

operands { 

#1 = { +0=0xE0; +1=#1; }; 

}; 

}; 

op iret { 

map iret: OxEl; // 11100001 = iret 

operands { - = { +0=0xEl; }; }; 

}; 

// 


op imrl { 

map imrl: 0xE2; // 11100010 = IMR load 

operands { 

#1 = { +0=0xE2; +1=#1[7:0]; }; 

}; 

operands { - = { +0=0xE2; }; }; 

}; 

op ivtl { 

map ivtl: 0xE3; // 11100011 = IVT load 

operands { 

#1 = { +0=0xE3; +1=#1[7:0]; +2=#1[15:8]; }; 

}; 

}; 

// 


op flag_i { 

map flag_i_clr: 0xE4; // 11100100 = flag_i 0 
map flag_i_set: 0xE5; // 11100101 = flag_i 1 

operands { 

#1 = { +0=0xE4; +0[0:0]=#1; }; 

}; 

}; 



Version "E" 


1017 


// 



op flag_c { 



map flag_c_clr: 0xE6; 

// 11100110 

= flagc 0 

map flag_c_set: 0xE7; 

// 11100111 

= flagc 1 

operands { 



#1 = { +0=0xE6; +0[0 

}; 

:0]=#1; }; 


}; 

// 



op in { 



map in_num_a: 0xE8; 

// 11101000 

= in <n>, %A 

map in_num_b: 0xE9; 

// 11101001 

= in <n>, %B 

map in_num_mi: OxEA; 

// 11101010 

= in <n>, (%I) 

map in_num_mj: OxEB; 

// 11101011 

= in <n>, (%J) 

operands { 



#1,%2 = { +0=0xE8; 

+0[0:0]=%2; 

+1=#1; }; 

#1, (%2) = { +0 = 0xEA; 

}; 

+0[0:0]=%2; 

+1=#1; }; 

}; 

op out { 



map out_a_num: OxEC; 

// 11101100 

= out %A, # 

map out_b_num: OxED; 

// 11101101 

= out %B, # 

map out_mi_num: OxEE; 

// 11101110 

= out (%I) , # 

map out_mi_num: OxEF; 

// 11101111 

= out (%J) , # 

operands { 



% 1, #2 = { +0=0xEC; 

+0[0:0]=%1; 

+1=#2; }; 

(%1),#2 = { +0=0xEE; 

}; 

+0[0:0]=%1; 

+1=#2; }; 

}; 

// 



op ifack_jump { 



map ifack_jump: OxFO; 

// 11110000 

= jump if ack from device 

operands { 



#1,#2 = { +0=0xF0; 

}; 

}; 

+1=#1; +2=#2[7:0]; +3=#2[15:8]; }; 



1018 


Version "E" 


op ifack_call { 
map ifack_call 
operands { 
# 1,#2 = { 

}; 

}; 

// 

op cmpr { 
map cmpr: 
operands { - = 

}; 

op testr { 
map testr: 
operands { - = 

}; 

// 

op cmpi { 
map cmpi: 
operands { - = 

}; 

op testi { 
map testi: 
operands { - = 

}; 

// 

op cmps { 
map cmps: 
operands { - = 

}; 

op tests { 
map tests: 
operands { - = 

}; 

// 

op cmp 8i { 
map cmp8i: 


: OxFl; // 11110001 = call if ack from device 

+0=0xFl; +1=#1; +2=#2[7:0]; +3=#2[15:8]; }; 


0xF2; // 11110010 * 

{ +0[7:0]=0xF2; }; }; 


0xF3; // 11110011 : 

{ +0[7:0]=0xF3; }; }; 


0xF4; // 11110100 : 

{ +0[7:0]=0xF 4; }; }; 


0xF5; // 11110101 * 

{ +0[7:0]=0xF5; }; }; 


compare %A , %B 


test %A, %B 


compare (%I), (%J) 


test (%I ), (%J) 


0xF6; // 11110110 = compare stack 

{ +0[7:0]=0xF6; }; }; 


0xF7; // 11110111 = test stack 

{ +0[7:0]=0xF7; }; }; 


0xF8; // 11111000 = compare8 (%I), (%J) 



Version "E" 


1019 


operands { - 

}; 

op test8i { 
map test8i: 
operands { - 

}; 

// 

op cmp 8 s { 
map cmp8s: 
operands { - 

}; 

op test8s { 
map test8s: 
operands { - 

}; 

// 

op stop { 
map stop: 
operands { - 

}; 


{ +0[7:0]=0xF8; }; }; 


0xF9; // 11111001 = tests (%I), (%J) 

{ +0 [7:0]=0xF9; }; }; 


OxFA; // 11111010 = compare8 stack 

{ +0[7:0]=0xFA; }; }; 


OxFB; // 11111011 = test8 stack 

{ +0 [ 7:0]=0xFB; }; }; 


OxFF; // 11111111 

{ +0[7:0]=0xFF; }; }; 


13.14 Microcode 

It follows the microcode listing, describing the opcode procedures. 
The microcode is much different from the previous version, because 
the bit fields have different names and because the memory is ac¬ 
cessed in a new slower way. Please notice that the fetch cycle is 
started with just fetch=f 1, but it requires two clock cycles and a 
separate ctrl=load is also required. 



1020 


Version "E" 


Listing 13.43. Microcode for TKGate. 


begin microcode @ 0 

// 

fetchl: 

// MAR <= PC++, MIR <= RAM == 

fetch=fl; 

mar=p mar=rank8 mar=load pc=dpl 

mir=ram_read; 

fetchO: 

// MIR <= RAM , MFC <= MIR 

ctrl=load; 

// 

nop: 

// MFC <= #fetch 

addr=fetchl jump=true; 

// 

c P_i_j: 

fetch=fl j=a j=load i=a i=bw; 

// j <= i 

ctrl=load; 

cp_i_a: 

fetch=fl a=a a=load i=a i=bw; 

// A <= I 

ctrl=load; 

cp_i_b: 

fetch=fl b=a b=load i=a i=bw; 

// B <= I 

ctrl=load; 

cp_i_sp: 

fetch=fl sp=a sp=load i=a i=bw; 

// SP <= I 

ctrl=load; 

cp_i_bp: 

fetch=fl bp=a bp=load i=a i=bw; 

// BP <= I 

ctrl=load; 

cp_i_c: 

fetch=fl c=a c=load i=a i=bw; 

// C <= I 

ctrl=load; 

cp_i_f1: 

fetch=fl fl=a fl=load i=a i=bw; 

// FL <= I 

ctrl=load; 

cp_ j_i : 

fetch=fl i=a i=load j=a j=bw; 

// I <= J 

ctrl=load; 

cp_j_a: 

fetch=fl a=a a=load j=a j=bw; 

// A <= J 

ctrl=load; 

cp_j_b: 

fetch=fl b=a b=load j=a j=bw; 

// B <= J 



Version "E" 


1021 


ctrl=load; 

cp_j_sp: 

fetch=fl sp=a sp=load j=a j=bw; 

// SP <= J 

ctrl=load; 

cp_j_bp: 

fetch=fl bp=a bp=load j=a j=bw; 

// BP <= J 

ctrl=load; 

cp_j_c: 

fetch=fl c=a c=load j=a j=bw; 

// C <= J 

ctrl=load; 

cp_j_fl: 

fetch=fl fl=a fl=load j=a j=bw; 

// FL <= J 

ctrl=load; 

cp_a_i: 

fetch=fl i=a i=load a=a a=bw; 

// I <= A 

ctrl=load; 

cp_a_j: 

fetch=fl j=a j=load a=a a=bw; 

// J <= A 

ctrl=load; 

cp_a_b: 

fetch=fl b=a b=load a=a a=bw; 

// B <= A 

ctrl=load; 

cp_a_sp: 

fetch=fl sp=a sp=load a=a a=bw; 

// SP <= A 

ctrl=load; 

cp_a_bp: 

fetch=fl bp=a bp=load a=a a=bw; 

// BP <= A 

ctrl=load; 

cp_a_c: 

fetch=fl c=a c=load a=a a=bw; 

// C <= A 

ctrl=load; 

cp_a_f1: 

fetch=fl fl=a fl=load a=a a=bw; 

// FL <= A 

ctrl=load; 

cp_b_i: 

fetch=fl i=a i=load b=a b=bw; 

// I <= B 

ctrl=load; 

c P_b_j: 

fetch=fl j=a j=load b=a b=bw; 

// J <= B 

ctrl=load; 

cp_b_a: 

fetch=fl a=a a=load b=a b=bw; 

// A <= B 

ctrl=load; 




1022 


Version "E" 


cp_b_sp: 

fetch=fl sp=a sp=load b=a b=bw; 

// SP <= B 

ctrl=load; 

cp_b_bp: 

fetch=fl bp=a bp=load b=a b=bw; 

// BP <= B 

ctrl=load; 

cp_b_c: 

fetch=fl c=a c=load b=a b=bw; 

// C <= B 

ctrl=load; 

cp_b_f1: 

fetch=fl fl=a fl=load b=a b=bw; 

// FL <= B 

ctrl=load; 

cp_sp_i: 

fetch=fl i=a i=load sp=a sp=bw; 

// I <= SP 

ctrl=load; 

cp_sp_j: 

fetch=fl j=a j=load sp=a sp=bw; 

// J <= SP 

ctrl=load; 

cp_sp_a: 

fetch=fl a=a a=load sp=a sp=bw; 

// A <= SP 

ctrl=load; 

cp_sp_b: 

fetch=fl b=a b=load sp=a sp=bw; 

// B <= SP 

ctrl=load; 

cp_sp_bp: 

fetch=fl bp=a bp=load sp=a sp=bw; 

// BP <= SP 

ctrl=load; 

cp_sp_c: 

fetch=fl c=a c=load sp=a sp=bw; 

// C <= SP 

ctrl=load; 

cp_sp_f1: 

fetch=fl fl=a fl=load sp=a sp=bw; 

// FL <= SP 

ctrl=load; 

cp_bp_i: 

fetch=fl i=a i=load bp=a bp=bw; 

// I <= BP 

ctrl=load; 

cp_bp_j: 

fetch=fl j=a j=load bp=a bp=bw; 

// J <= BP 

ctrl=load; 

cp_bp_a: 

fetch=fl a=a a=load bp=a bp=bw; 

// A <= BP 

ctrl=load; 

cp_bp_b: 




Version "E" 


1023 


fetch=fl b=a b=load bp=a bp=bw; 

// B <= BP 

ctrl=load; 

cp_bp_sp: 

fetch=fl sp=a sp=load bp=a bp=bw; 

// SP <= BP 

ctrl=load; 

cp_bp_c: 

fetch=fl c=a c=load bp=a bp=bw; 

// C <= BP 

ctrl=load; 

cp_bp_f1: 

fetch=fl fl=a fl=load bp=a bp=bw; 

// FL <= BP 

ctrl=load; 

cp_c_i: 

fetch=fl i=a i=load c=a c=bw; 

// I <= C 

ctrl=load; 

cp_c_j: 

fetch=fl j=a j=load c=a c=bw; 

// J <= C 

ctrl=load; 

cp_c_a: 

fetch=fl a=a a=load c=a c=bw; 

// A <= C 

ctrl=load; 

cp_c_b: 

fetch=fl b=a b=load c=a c=bw; 

// B <= C 

ctrl=load; 

cp_c_sp: 

fetch=fl sp=a sp=load c=a c=bw; 

// SP <= C 

ctrl=load; 

cp_c_bp: 

fetch=fl bp=a bp=load c=a c=bw; 

// BP <= C 

ctrl=load; 

cp_c_f1: 

fetch=fl fl=a fl=load c=a c=bw; 

// FL <= C 

ctrl=load; 

cp_fl_i: 

fetch=fl i=a i=load fl=a fl=bw; 

// I <= FL 

ctrl=load; 

cp_fl_j : 

fetch=fl j=a j=load fl=a fl=bw; 

// J <= FL 

ctrl=load; 

cp_fl_a: 

fetch=fl a=a a=load fl=a fl=bw; 

// A <= FL 

ctrl=load; 

cp_fl_b: 

fetch=fl b=a b=load fl=a fl=bw; 

// B <= FL 



1024 


Version "E" 


ctrl=load; 
cp_fl_sp: 

fetch=fl sp=a sp=load fl=a fl=bw; // SP <= FL 
ctrl=load; 
cp_fl_bp: 

fetch=fl bp=a bp=load fl=a fl=bw; // BP <= FL 
ctrl=load; 
cp_fl_c: 

fetch=fl c=a c=load fl=a fl=bw; // C <= FL 

ctrl=load; 
cp_num_i: 

// MAR <= PC+=2, MDR <= RAM (3 clocks) ; 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// I <= MDR; 

fetch=fl i=a i=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_num_j: 

// MAR <= PC+=2, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// J <= MDR; 

fetch=fl j=a j=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_num_a: 

// MAR <= PC+=2, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// A <= MDR; 

fetch=fl a=a a=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_num_b: 

// MAR <= PC+=2, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

fetch=fl b=a b=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_mi_a: 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=i mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// A <= MDR; 

fetch=fl a=a a=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_mi_b: 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=i mar=rank!6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 



Version "E" 


1025 


// B <= MDR; 

fetch=fl b=a b=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_mj_a: 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=j mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// A <= MDR; 

fetch=fl a=a a=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_mj_b: 

// MAR <= J , MDR <= RAM (3 clocks); 

mar=j mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

fetch=fl b=a b=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
cp_a_mi: 

// MDR <= A 

mdr=a mdr=load a=bw; 

// MAR <= I, RAM <= MDR (3 clocks) 

mar=i mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
cp_a_mj: 

// MDR <= A 

mdr=a mdr=load a=bw; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=j mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
cp_b_mi: 

// MDR <= B 

mdr=a mdr=load b=bw; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=i mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
cp_b_mj: 

// MDR <= B 

mdr=a mdr=load b=bw; 

// MAR <= JV RAM <= MDR (3 clocks) 

mar=j mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
cp_num_mi: 

// MAR <= PC+=2, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// MAR <= I, RAM <= MDR (3 clocks) 



1026 


Version "E" 


mar=i mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
cp_num_mj: 

// MAR <= PC+=2, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// MAR <= J , RAM <= MDR (3 clocks) 

mar=j mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
cp_mi_mj: 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=i mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// MAR <= J , RAM <= MDR (3 clocks) 

mar=j mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
cp_mj_mi: 

// MAR <= J , MDR <= RAM (3 clocks); 

mar=j mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=i mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
cp8_num_i: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// I <= MDR; 

fetch=fl i=a i=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
cp8_num_j: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// J <= MDR; 

fetch=fl j=a j=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
cp8_num_a: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// A <= MDR; 

fetch=fl a=a a=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
cp8_num_b: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// B <= MDR; 

fetch=fl b=a a=load mdr=a mdr=rank8u mdr=bw; 



Version "E" 


1027 


ctrl=load; 
cp8_mi_a: 

// MAR <= J, MDR <= RAM (2 clocks); 

mar=i mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// A <= MDR; 

fetch=fl a=a a=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
cp8_mi_b: 

// MAR <= J, MDR <= RAM (2 clocks); 

mar=i mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// B <= MDR; 

fetch=fl b=a a=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
cp8_mj_a: 

// MAR <= J, MDR <= RAM (2 clocks); 

mar=j mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// A <= MDR; 

fetch=fl a=a a=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
cp8_mj_b: 

// MAR <= J , MDR <= RAM (2 clocks); 

mar=j mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// B <= MDR; 

fetch=fl b=a a=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
cp8_a_mi: 

// MDR <= A 

mdr=a mdr=load a=bw; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=i mar=rank8 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
cp8_a_mj: 

// MDR <= A 

mdr=a mdr=load a=bw; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=j mar=rank8 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
cp8_b_mi: 

// MDR <= B 

mdr=a mdr=load b=bw; 

// MAR <= I, RAM <= MDR (3 clocks) 

mar=i mar=rank8 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 



1028 


Version "E" 


cp8_b_mj: 

// MDR <= A 

mdr=a mdr=load b=bw; 

// MAR <= J , RAM <= MDR (3 clocks) 

mar=j mar=rank8 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
cp8_num_mi: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dp2 mdr=ram_read; ctrl=nop; 

// MAR <= J, RAM <= MDR (2 clocks) 

mar=i mar=rank8 mar=load mar=ram_write; ctrl=nop; 
fetch=f1; ctrl=load; 
cp8_num_mj: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dp2 mdr=ram_read; ctrl=nop; 

// MAR <= J, RAM <= MDR (2 clocks) 

mar=j mar=rank8 mar=load mar=ram_write; ctrl=nop; 
fetch=f1; ctrl=load; 
cp8_mi_mj: 

// MAR <= J, MDR <= RAM (2 clocks); 

mar=i mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// MAR <= J, RAM <= MDR (2 clocks) 

mar=j mar=rank8 mar=load mar=ram_write; ctrl=nop; 
fetch=f1; ctrl=load; 
cp8_mj_mi: 

// MAR <= J , MDR <= RAM (2 clocks); 

mar=j mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// MAR <= J, RAM <= MDR (2 clocks) 

mar=i mar=rank8 mar=load mar=ram_write; ctrl=nop; 
fetch=f1; ctrl=load; 
push_i: 

// MDR <= I 

mdr=a mdr=load i=a i=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
push_j: 

// MDR <= J 

mdr=a mdr=load j=a j=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
push_a: 



Version "E" 


1029 


// MDR <= A 

mdr=a mdr=load a=a a=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
push_b: 

// MDR <= B 

mdr=a mdr=load b=a b=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
push_bp: 

// MDR <= BP 

mdr=a mdr=load bp=a bp=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
push_sp: 

// MDR <= SP 

mdr=a mdr=load sp=a sp=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
push_c: 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
push_f1: 

// MDR <= FL 

mdr=a mdr=load fl=a fl=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
push_num: 

// MAR <= PC++, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
push_mi: 

// MAR <= I, MDR <= RAM (3 clocks); 



1030 


Version "E" 


mar=i mar=rankl6 mar=load mdr=ram_read; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write 
fetch=f1; ctrl=load; 
push_mj: 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=j mar=rankl6 mar=load mdr=ram_read; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write 
fetch=fl; ctrl=load; 
pop_i: 


ctrl=nop; ctrl=nop; 
sp=qm2 sp=qup; ctrl=nop; 

ctrl=nop; ctrl=nop; 
sp=qm2 sp=qup; ctrl=nop; 


ctrl=nop; 


ctrl=nop; 


// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// I <= MDR; 

fetch=fl i=a i=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_j: 


// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// J <= MDR; 

fetch=fl j=a j=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_a: 


// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rank!6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 


// A <= MDR; 


fetch=fl a=a a=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_b: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

fetch=fl b=a b=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_bp: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// BP <= MDR; 

fetch=fl bp=a bp=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_sp: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rank!6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 



Version "E" 


1031 


// SP <= MDR; 

fetch=fl sp=a sp=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_c: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= MDR; 

fetch=fl c=a c=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_f1: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// FL <= MDR; 

fetch=fl fl=a fl=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
pop_mi: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// MAR <= I, RAM <= MDR (3 clocks) 

mar=i mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
pop_mj: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=j mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
push8_i: 

// MDR <= I 

mdr=a mdr=load i=a i=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
push8_j: 

// MDR <= J 

mdr=a mdr=load j=a j=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
push8_a: 

// MDR <= A 

mdr=a mdr=load a=a a=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 



1032 


Version "E" 


mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
push8_b: 

// MDR <= B 

mdr=a mdr=load b=a b=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
push8_bp: 

// MDR <= BP 

mdr=a mdr=load bp=a bp=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
push8_sp: 

// MDR <= SP 

mdr=a mdr=load sp=a sp=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
push8_c: 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
push8_f1: 

// MDR <= FL 

mdr=a mdr=load fl=a fl=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
push8_num: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
push8_mi: 

// MAR <= I, MDR <= RAM (2 clocks); 

mar=i mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 



Version "E" 


1033 


fetch=f1; ctrl=load; 

push8_mj: 

// MAR <= J , MDR <= RAM (2 clocks); 

mar=j mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml 

sp=qup; ctrl=nop; 

fetch=fl; ctrl=load; 

pop8_i: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; 

ctrl=nop; 

// I <= MDR; 

fetch=fl i=a i=load mdr=a mdr=rank8u mdr=bw; 

ctrl=load; 

pop8_j: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; 

ctrl=nop; 

// J <= MDR; 

fetch=fl j=a j=load mdr=a mdr=rank8u mdr=bw; 

ctrl=load; 

pop8_a: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; 

ctrl=nop; 

// A <= MDR; 

fetch=fl a=a a=load mdr=a mdr=rank8u mdr=bw; 

ctrl=load; 

pop8_b: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; 

ctrl=nop; 

// B <= MDR; 

fetch=fl b=a b=load mdr=a mdr=rank8u mdr=bw; 

ctrl=load; 

pop8_bp: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; 

ctrl=nop; 

// BP <= MDR; 

fetch=fl bp=a bp=load mdr=a mdr=rank8u mdr=bw; 

ctrl=load; 

pop8_sp: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; 

ctrl=nop; 

// SP <= MDR; 

fetch=fl sp=a sp=load mdr=a mdr=rank8u mdr=bw; 

ctrl=load; 




1034 


Version "E" 


pop8_c: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= MDR; 

fetch=fl c=a c=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
pop8_f1: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// FL <= MDR; 

fetch=fl fl=a fl=load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 
pop8_mi: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// MAR <= I, RAM <= MDR (2 clocks) 

mar=i mar=rank8 mar=load mar=ram_write; ctrl=nop; 
fetch=f1; ctrl=load; 
pop8_mj: 

// MAR <= SP++, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// MAR <= J, RAM <= MDR (2 clocks) 

mar=j mar=rank8 mar=load mar=ram_write; ctrl=nop; 
fetch=f1; ctrl=load; 
jump: 

// MAR <= PC+=2, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// PC <= MDR; 

pc=a pc=load mdr=a mdr=rankl6 mdr=bw; 
fetch=f1; ctrl=load; 
jump_nc: 

// check flag before reading the destination argument 

addr=jump jump=carry_f; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
j ump_c: 

// check flag before reading the destination argument 

addr=jump jump=carry_t; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
jump_nz: 



Version "E" 


1035 


// check flag before reading the destination argument 

addr=jump jump=zero_f; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
jump_z: 

// check flag before reading the destination argument 

addr=jump jump=zero_t; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
jump_nn: 

// check flag before reading the destination argument 

addr=jump jump=negative_f; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
j ump_n: 

// check flag before reading the destination argument 

addr=jump jump=negative_t; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
jump_no: 

// check flag before reading the destination argument 

addr=jump jump=overflow_f; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
j ump_o: 

// check flag before reading the destination argument 

addr=jump jump=overflow_t; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
equal: 

// C <= A (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=a alu=rankl6 a=a a=bw; 
ctrl=load; 

not: 

// c <= ~A (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=not alu=rankl6 a=a a=bw; 
ctrl=load; 



1036 


Version "E" 


and: 

// C <= A&B (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=and alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 
nand: 

// c <= ~(A&B) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=nand alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 

or: 

// C <= A IB (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=or alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 

nor: 

// c <= ~(A\B) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=nor alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 

xor: 

// C <= A A B (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=xor alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 
nxor: 

// c <= ~(A*B) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=nxor alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 

add: 

// C <= A+B (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=add alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 

sub: 

// C <= A—B (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=sub alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 
addc: 

// C <= A+B+carry (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=addc alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 
subb: 

// C <= A-B-borrow (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=subb alu=rankl6 a=a a=bw b=b b=bw; 
ctrl=load; 
lshl: 

// C <= lshl (A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=lshl alu=rankl6 a=a a=bw; 



Version "E" 


1037 


ctrl=load; 
lshr: 

// C <= lshr (A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=lshr alu=rankl6 a=a a=bw; 
ctrl=load; 
ashl: 


// C <= ashl (A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=ashl alu=rankl6 a=a a=bw; 
ctrl=load; 
ashr: 

// C <= ashr (A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=ashr alu=rankl6 a=a a=bw; 
ctrl=load; 
rotcl: 

// C <= rotcl (A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rotcl alu=rankl6 a=a a=bw; 
ctrl=load; 
rotcr: 

// C <= rotcr(A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rotcr alu=rankl6 a=a a=bw; 
ctrl=load; 
rot 1: 


// C <= rotl(A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rotl alu=rankl6 a=a a=bw; 
ctrl=load; 
rot r: 

// C <= rotr (A) (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rotr alu=rankl6 a=a a=bw; 
ctrl=load; 
add8 : 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=add8 alu=rank8u a=a a=bw b=b b=bw; 
ctrl=load; 
sub8 : 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=sub8 alu=rank8u a=a a=bw b=b b=bw; 
ctrl=load; 
add8c: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=add8c alu=rank8u a=a a=bw b=b b=bw; 
ctrl=load; 
sub8b: 

// C <= A[7:0]+B[7:0] (FL updated) 



1038 


Version "E" 


fetch=fl c=b c=load fl=b fl=load alu=sub8b alu=rank8u a=a a=bw b=b b=bw; 
ctrl=load; 
lsh81: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=lsh81 alu=rank8u a=a a=bw; 
ctrl=load; 
lsh8r: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=lsh8r alu=rank8u a=a a=bw; 
ctrl=load; 
ash81: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=ash81 alu=rank8u a=a a=bw; 
ctrl=load; 
ash8r: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=ash8r alu=rank8u a=a a=bw; 
ctrl=load; 
rot8cl: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rot8cl alu=rank8u a=a a=bw; 
ctrl=load; 
rot8cr: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rot8cr alu=rank8u a=a a=bw; 
ctrl=load; 
rot81: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rot81 alu=rank8u a=a a=bw; 
ctrl=load; 
rot8r: 

// C <= A[7:0]+B[7:0] (FL updated) 

fetch=fl c=b c=load fl=b fl=load alu=rot8r alu=rank8u a=a a=bw; 
ctrl=load; 
cast_uns_a: 

c=b c=load fl=b fl=load alu=a alu=rank8u a=a a=bw; 
fetch=fl a=a a=load c=a c=bw 
ctrl=load; 
cast_uns_b: 

c=b c=load fl=b fl=load alu=a alu=rank8u b=a b=bw; 
fetch=fl b=a b=load c=a c=bw 
ctrl=load; 
cast_sig_a: 



Version "E" 


1039 


c=b c=load fl=b fl=load alu=a alu=rank8s a=a a=bw; 
fetch=fl a=a a=load c=a c=bw 
ctrl=load; 
cast_sig_b: 

c=b c=load fl=b fl=load alu=a alu=rank8s b=a b=bw; 
fetch=fl b=a b=load c=a c=bw 
ctrl=load; 
equals: 

// MAR <= SP, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// C <= MDR (FL updated) 

c=b c=load fl=b fl=load alu=a alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 
fetch=fl; ctrl=load; 
not s : 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// c <= -'MDR (FL updated) 

c=b c=load fl=b fl=load alu=not alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
ands : 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// C <= A&B (FL updated) 

c=b c=load fl=b fl=load alu=and alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
nands: 

// MAR <= SP=+2 f MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 



1040 


Version "E" 


a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// c <= ~(A&B) (FL updated) 

c=b c=load fl=b fl=load alu=nand alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 

ors : 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// C <= A!B (FL updated) 

c=b c=load fl=b fl=load alu=or alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
nors : 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// c <= ~(A\B) (FL updated) 

c=b c=load fl=b fl=load alu=nor alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 



Version "E" 


1041 


fetch=f1; ctrl=load; 


xors: 


// MAR <= SP=+2, 

MDR <= RAM (3 clocks); 

mar=s mar=rankl6 

mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <- MDR; 



a=a a=load mdr=a mdr=rankl6 mdr=bw; 


// MAR <~ SP=+2, 

MDR <= RAM (3 clocks); 

mar=s mar=rankl6 

mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 



b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// C <= A A B (FL updated) 

c=b c=load fl=b fl=load alu=xor alu=rank!6 a=a a=bw b=b b=bw; 


// MDR <= C 


mdr=a mdr=load c= 

II 

QJ 

o 

II 

tr 

3 

// MAR <= SP=—2, 

RAM <- MDR (3 clocks) 


mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 


nxors: 


// MAR <= SP=+2, 

MDR <= RAM (3 clocks); 

mar=s mar=rankl6 

mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <- MDR; 



a=a a=load mdr=a mdr=rankl6 mdr=bw; 


// MAR <= SP=+2, 

MDR <- RAM (3 clocks); 

mar=s mar=rankl6 

mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 



b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// c <= ~(A*B) (FL updated) 

c=b c=load fl=b fl=load alu=nxor alu=rank!6 a=a a=bw b=b b=bw; 


// MDR <= C 


mdr=a mdr=load c= 

II 

QJ 

o 

II 

tr 

3 

// MAR <= SP=—2, 

RAM <- MDR (3 clocks) 


mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 


adds: 


// MAR <= SP=+2, 

MDR <= RAM (3 clocks); 

mar=s mar=rankl6 

mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 



a=a a=load mdr=a mdr=rankl6 mdr=bw; 


// MAR <= SP=+2, 

MDR <= RAM (3 clocks); 

mar=s mar=rankl6 

mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 



b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// C <= A+B (FL updated) 



1042 


Version "E" 


c=b c=load fl=b fl=load alu=add alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
subs : 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// C <= A—B (FL updated) 

c=b c=load fl=b fl=load alu=sub alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
addcs: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// C <= A+B+carry (FL updated) 

c=b c=load fl=b fl=load alu=addc alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
subbs: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 



Version "E" 


1043 


// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// C <= A-B-borrow (FL updated) 

c=b c=load fl=b fl=load alu=subb alu=rankl6 a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
lshls: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= lshl (A) (FL updated) 

c=b c=load fl=b fl=load alu=lshl alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
lshrs: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= lshr(A) (FL updated) 

c=b c=load fl=b fl=load alu=lshr alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
ashls: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= ashl (A) (FL updated) 

c=b c=load fl=b fl=load alu=ashl alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
ashrs: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 



1044 


Version "E" 


mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= ashr(A) (FL updated) 

c=b c=load fl=b fl=load alu=ashr alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=—2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
rotcls: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= rotcl (A) (FL updated) 

c=b c=load fl=b fl=load alu=rotcl alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
rotcrs: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= rotcr(A) (FL updated) 

c=b c=load fl=b fl=load alu=rotcr alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
rotIs : 

// MAR <= SP=+2, MDR <= RAM (3 clocks ); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= rotl(A) (FL updated) 

c=b c=load fl=b fl=load alu=rotl alu=rankl6 mdr=a mdr=rankl6 mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
rotrs: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// C <= rotr(A) (FL updated) 

c=b c=load fl=b fl=load alu=rotr alu=rank!6 mdr=a mdr=rank!6 mdr=bw; 



Version "E" 


1045 


// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
add8s: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8u mdr=bw; 

// C <= A+B (FL updated) 

c=b c=load fl=b fl=load alu=add8 alu=rank8u a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
sub8s: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8u mdr=bw; 

// C <= A—B (FL updated) 

c=b c=load fl=b fl=load alu=sub8 alu=rank8u a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
add8cs: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= ++SP, MDR <= RAM (2 clocks); 



1046 


Version "E" 


mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8u mdr=bw; 

// C <= A+B+carry (FL updated) 

c=b c=load fl=b fl=load alu=add8c alu=rank8u a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
sub8bs: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8u mdr=bw; 

// C <= A-B-borrow (FL updated) 

c=b c=load fl=b fl=load alu=sub8b alu=rank8u a=a a=bw b=b b=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
lsh81s: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= lsh81 (A) (FL updated) 

c=b c=load fl=b fl=load alu=lsh81 alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
lsh8rs: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= lsh8r (A) (FL updated) 

c=b c=load fl=b fl=load alu=lsh8r alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 



Version "E" 


1047 


// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
ash81s: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= ash81 (A) (FL updated) 

c=b c=load fl=b fl=load alu=ash81 alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
ash8rs: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= ash8r (A) (FL updated) 

c=b c=load fl=b fl=load alu=ash8r alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
rot8cls: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= rot8cl(A) (FL updated) 

c=b c=load fl=b fl=load alu=rot8cl alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
rot8crs: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= rot8cr(A) (FL updated) 

c=b c=load fl=b fl=load alu=rot8cr alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 



1048 


Version "E" 


rot81s: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= rot81 (A) (FL updated) 

c=b c=load fl=b fl=load alu=rot81 alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=fl; ctrl=load; 
rot8rs: 

// MAR <= ++SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=dpl; ctrl=nop; 

// C <= rot8r (A) (FL updated) 

c=b c=load fl=b fl=load alu=rot8r alu=rank8u mdr=a mdr=rank8u mdr=bw; 

// MDR <= C 

mdr=a mdr=load c=a c=bw; 

// MAR <= — SP, RAM <= MDR (2 clocks) 

mar=s mar=rank8 mar=load mar=ram_write sp=qml sp=qup; ctrl=nop; 
fetch=f1; ctrl=load; 
casts_uns: 

// MAR <= SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// C <= MDR (FL updated) 

c=b c=load fl=b fl=load alu=a alu=rank8u mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
casts_sig: 

// MAR <= SP, MDR <= RAM (2 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// C <= MDR (FL updated) 

c=b c=load fl=b fl=load alu=a alu=rank8s mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
call: 

// MAR <= PC+=2, MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// TMP <= MDR 

tmp=a tmp=load mdr=a mdr=rankl6 mdr=bw; 

// MDR <= PC 

mdr=a mdr=load pc=a pc=bw; 



Version "E" 


1049 


// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 

// PC <= TMP 

pc=a pc=load tmp=a tmp=bw; 
fetch=fl; ctrl=load; 
call_i: 

// MDR <= PC 

mdr=a mdr=load pc=a pc=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 

// PC <= I 

pc=a pc=load i=a i=bw; 
fetch=fl; ctrl=load; 
call_j: 

// MDR <= PC 

mdr=a mdr=load pc=a pc=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; ctrl=nop; 

// PC <= J 

pc=a pc=load j=a j=bw; 
fetch=fl; ctrl=load; 
return: 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// SP <= MDR; 

fetch=fl sp=a sp=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
ivt 1: 

// MAR <= PC+=2 r MDR <= RAM (3 clocks); 

mar=p mar=rankl6 mar=load pc=dp2 mdr=ram_read; ctrl=nop; ctrl=nop; 

// IVT <= MDR 

fetch=fl ivt=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 

int: 

// 

// push FL 

// 

// MDR <= FL 

mdr=a mdr=load fl=a fl=bw; 

// MAR <= SP=—2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; 

// 

// Reset interrupt enable flag (while the MEM module is working). 



1050 


Version "E" 


// 

fl=b fl=load alu=cleari; 

// 

// push (PC+1) to jump over the interrupt argument. 

// 

// MDR <= PC+1 

mdr=a mdr=load pc=a pc=qpl pc=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; 

// 

// Convert the interrupt number from the argument, to the 
// interrupt vector table item address: 

// TMP <= IVT [int ], int <= RAM [PC] 

// 

// MAR <= PC++, MDR <~ RAM (2 clocks); 

mar=p mar=rankl6 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// TMP <= IVT [int] 

tmp=a tmp=load ivt=int_b ivt=bw mdr=b mdr=rank8u mdr=bw; 

// 

// Prepare to call the interrupt routine, loading the 
// interrupt vector table item address into PC. 

// 

// MAR <= TMP, MDR <= RAM (3 clocks); 

mar=t mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// PC <= MDR; 

fetch=fl pc=a pc=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 
iret: 

// 

// Pop PC 

// 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// PC <= MDR; 

pc=a pc=load mdr=a mdr=rankl6 mdr=bw; 

// 

// Pop FL 

// 

// MAR <= SP=+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=dp2; ctrl=nop; ctrl=nop; 

// FL <= MDR; 

fetch=fl fl=a fl=load mdr=a mdr=rankl6 mdr=bw; 
ctrl=load; 



Version "E" 


1051 


imrl: 

// MAR <= PC++, MDR <= RAM (2 clocks); 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// IRQ <= MDR; 

fetch=fl irq=mask_load mdr=a mdr=rank8u mdr=bw; 
ctrl=load; 

irq: 

// 

// push FL 

// 

// MDR <= FL 

mdr=a mdr=load fl=a fl=bw; 

// MAR <= SP=—2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; 

// 

// Reset interrupt enable flag (while the MEM module is working). 

// 

fl=b fl=load alu=cleari; 

// 

// push (PC-1) to jump back to the opcode just read. 

// 

// MDR <= PC-1 

mdr=a mdr=load pc=a pc=qml pc=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; 

// 

// Convert the interrupt number from the IRQ module, to the 
// interrupt vector table item address: 

// TMP <= IVT [int], int <= IRQ 

// 

// TMP <= IVT [INT[IRQ]] 

tmp=a tmp=load ivt=int_a ivt=bw; 

// 

// Prepare to call the interrupt routine, loading the 
// interrupt vector table item address into PC. 

// 

// MAR <= TMP, MDR <= RAM (3 clocks); 

mar=t mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// PC <= MDR; 

pc=a pc=load mdr=a mdr=rankl6 mdr=bw; 

// 

// Set the IRQ received as already done. 

// 



1052 


Version "E" 


// 

fetch=fl irq=irq_done; 
ctrl=load; 
op_error: 

// 

// push FL 

// 

// MDR <= FL 

mdr=a mdr=load fl=a fl=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; 

// 

// Reset interrupt enable flag (while the MEM module is working) . 

// 

fl=b fl=load alu=cleari; 

// 

// push (PC-1) to jump back to the opcode just read. 

// 

// MDR <= PC-1 

mdr=a mdr=load pc=a pc=qml pc=bw; 

// MAR <= SP=-2, RAM <= MDR (3 clocks) 

mar=s mar=rankl6 mar=load mar=ram_write sp=qm2 sp=qup; ctrl=nop; 

// 

// Convert the interrupt number 0 to the 
// interrupt vector table item address: 

// 

// TMP <= IVT[0] 

tmp=a tmp=load ivt=int_b ivt=bw bus=b bus=bw bus=0; 

// 

// Prepare to call the interrupt routine, loading the 
// interrupt vector table item address into PC. 

// 

// MAR <= TMP, MDR <= RAM (3 clocks); 

mar=t mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// PC <= MDR; 

pc=a pc=load mdr=a mdr=rankl6 mdr=bw; 
fetch=f1; 
ctrl=load; 
flag_i_clr: 

// FL <= FL&OxFFEF 

fetch=fl fl=b fl=load alu=cleari; 
ctrl=load; 
flag_i_set: 



Version "E" 


1053 


// FL <= FL10x0010 

fetch=fl fl=b fl=load alu=seti; 
ctrl=load; 
flag_c_clr: 

// FL <= FL&OxFFFE 

fetch=fl fl=b fl=load alu=clearc; 
ctrl=load; 
flag_c_set: 

// FL <= FLI 0x0001 

fetch=fl fl=b fl=load alu=setc; 
ctrl=load; 
in_num_a: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// IOA <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// I/O request (2 clocks) 

ioc=req; ctrl=nop; 

ctrl=nop; 

ctrl=nop; 

// A <= IOC 
a=a a=load ioc=bw; 
ctrl=nop; 
ctrl=nop; 
fetch=f1; 
ctrl=load; 
in_num_b: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dp2 mdr=ram_read; ctrl=nop; 

// IOA <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// I/O request (2 clocks) 

ioc=req; ctrl=nop; 

// B <= IOC 

fetch=fl b=a b=load ioc=bw; 
ctrl=load; 
in_num_mi: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dp2 mdr=ram_read; ctrl=nop; 

// IOA <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// I/O request (2 clocks) 

ioc=req; ctrl=nop; 



1054 


Version "E" 


// MDR <= IOC 

mdr=a mdr=load ioc=bw; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=i mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=fl; ctrl=load; 
in_num_mj: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dp2 mdr=ram_read; ctrl=nop; 

// 10A <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// I/O request (2 clocks) 

ioc=req; ctrl=nop; 

// MDR <= IOC 

mdr=a mdr=load ioc=bw; 

// MAR <= J, RAM <= MDR (3 clocks) 

mar=j mar=rankl6 mar=load mar=ram_write; ctrl=nop; ctrl=nop; 
fetch=f1; ctrl=load; 
out_a_num: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// 10A <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// IOC <= A 

ioc=load a=a a=bw; 

// I/O request 

ioc=req 

fetch=f1; ctrl=load; 
out_b_num: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// 10A <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// IOC <= B 

ioc=load b=a b=bw; 

// I/O request 

ioc=req 

fetch=fl; ctrl=load; 
out_mi_num: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// 10A <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// MAR <= I, MDR <= RAM (3 clocks); 



Version "E" 


1055 


mar=i mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// IOC <= MDR; 

ioc=req 

fetch=f1; ctrl=load; 
out_mj_num: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// 10A <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=j mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// IOC <= MDR; 

ioc=req 

fetch=f1; ctrl=load; 
ifack_jump: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// 10A <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// C <= alu(I/0 isack) (FL updated) and conditional jump. 

c=b c=load fl=b fl=load alu=a alu=rank8s ioc=isack ioc=bw 
addr=jump jump=zero_f; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
ifack_call: 

// MAR <= PC++, MDR <= RAM (2 clocks) 

mar=p mar=rank8 mar=load pc=dpl mdr=ram_read; ctrl=nop; 

// IOA <= MDR 

ioa=a ioa=load mdr=a mdr=rank8u mdr=bw; 

// C <= alu(I/0 Isack) (FL updated) and conditional jump. 

c=b c=load fl=b fl=load alu=a alu=rank8s ioc=isack ioc=bw 
addr=call jump=zero_f; 

// discard destination address: ++PC and fetch 

pc=qp2 pc=qup fetch=fl; 
ctrl=load; 
cmpr: 

// FL(A-B) 

fetch=fl fl=b fl=load alu=sub alu=rankl6; 
ctrl=load; 
testr: 

// FL (A&B), MPC <= #fetch 

fetch=fl fl=b fl=load alu=and alu=rank!6; 



1056 


Version "E" 


ctrl=load; 
cmpi: 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=i mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= J, MDR <= RAM (3 clocks); 

mar=j mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw 
addr=cmpr jump=true; 
testi: 


// MAR <= J, MDR <= RAM (3 clocks); 

mar=i mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= J , MDR <= RAM (3 clocks); 

mar=j mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw 
addr=testr jump=true; 
cmps : 

// MAR <= SP, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=qp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rankl6 mdr=bw 
addr=cmpr jump=true; 
tests: 

// MAR <= SP , MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rankl6 mdr=bw; 

// MAR <= SP+2, MDR <= RAM (3 clocks); 

mar=s mar=rankl6 mar=load mdr=ram_read sp=qp2; ctrl=nop; ctrl=nop; 

// A <= MDR; 


a=a a=load mdr=a mdr=rankl6 mdr=bw 
addr=testr jump=true; 
cmp 8i: 

// MAR <= I, MDR <= RAM (2 clocks); 



Version "E" 


1057 


mar=i mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rank8s mdr=bw; 

// MAR <= J, MDR <= RAM (2 clocks); 

mar=j mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8s mdr=bw; 
addr=cmpr jump=true; 
test8i: 


// MAR <= J, MDR <= RAM (2 clocks); 

mar=i mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rank8s mdr=bw; 

// MAR <= J , MDR <= RAM (2 clocks); 

mar=j mar=rank8 mar=load mdr=ram_read; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8s mdr=bw; 
addr=and jump=true; 
cmp 8 s: 

// MAR <= SP, MDR <= RAM (3 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8s mdr=bw; 

// MAR <= SP+1, MDR <= RAM (3 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=qpl; ctrl=nop; ctrl=nop; 

// A <= MDR; 


a=a a=load mdr=a mdr=rank8s mdr=bw 
addr=cmpr jump=true; 
test8s: 


// MAR <= SP, MDR <= RAM (3 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read; ctrl=nop; ctrl=nop; 

// B <= MDR; 

b=a b=load mdr=a mdr=rank8s mdr=bw; 

// MAR <= SP+1, MDR <= RAM (3 clocks); 

mar=s mar=rank8 mar=load mdr=ram_read sp=qpl; ctrl=nop; ctrl=nop; 

// A <= MDR; 

a=a a=load mdr=a mdr=rank8s mdr=bw 
addr=testr jump=true; 


stop: 

ctrl=stop; 

// 



1058 


Version "E" 


end 


13.15 Macrocode 

As an example, the following listing shows a simple program that 
reads from the keyboard and prints the same text on the virtual 
screen. The keyboard input is read after a hardware interrupt. 

Listing 13.44. Macrocode example for TKGate. 

begin macrocode @ 0 
jump #start 
nop 

interrupt_vector_table: 


.short 

0x0025 

// 

CPU opcode error 

.short 

0x0024 

// 

CPU 

.short 

0x0024 

// 

CPU 

.short 

0x0024 

// 

CPU 

.short 

0x0024 

// 

IRQ rtc 

.short 

0x0026 

// 

IRQ keyboard 

.short 

0x0024 

// 

IRQ hard disk 

.short 

0x0024 

// 

IRQ 

.short 

0x0024 

// 

software 

.short 

0x0024 

// 

software 

.short 

0x0024 

// 

software 

.short 

0x0024 

// 

software 

.short 

0x0024 

// 

software 

.short 

0x0024 

// 

software 

.short 

0x0024 

// 

software 

.short 

0x0024 

// 

software 


default_interrupt_routine: 
iret 

op_code_error: 

stop 

keyboard: 

in 1,%A // keyboard read 




Version "E" 


1059 



equal 

// 

update flags 


jump %zero,1,#keyboard_end 

// 

if zero exit 


out %A,0 

// 

print on screen 

jump #keyboard 
keyboard_end: 

iret 

start: 

// 

continue 


cp 0x0080, %I 
cp %I, %SP 

// 

ivtl #interrupt_vector_table 

// 

// 

set stack bottom 


imrl OxOF 

// 

all IRQ accepted 

flag_i 1 

// 

keyboard_reset: 

// 

IRQ enabled 


in 1,%A 

// 

keyboard read. 


equal 

// 

update flags 

// 

loop: 

jump %zero,0,#keyboard_reset 

jump #loop 

// 

if not zero continue 

stop: 

end 

// never reach 

stop 

the end. 



1060 


Version "E" 



“from the ground up” I-2013c — Copyright © Daniele Giacomini — appunti2@gmail.com http://www.linkedin.com/in/appunti2/ 


1061 

Version 

leges 



Chapter 



32-bit registers, big-endian, privi- 


« 


14.1 General purpose modules. 1065 

14.2 Addition modules. 1069 

14.3 Multiple clock lines. 1073 

14.4 Bus . 1076 

14.5 Registers: simple and with post-increment. 1078 

14.6 Memory segmentation. 1080 

14.7 Module “DA” . 1082 

14.8 Module “CA” . 1083 

14.9 Modules “M” and “RAM”. 1084 

14.10 Module “IR”. 1090 

14.11 Module “MD”. 1091 

14.12 Module “IRQ” . 1093 

14.13 Module “IVT” . 1095 

14.14 Module “ALU”. 1096 

14.15 Module “FL”. 1105 

14.16 Module “TTY”. 1108 

14.17 Module “HDD” . 1113 

14.18 Module “CTRL” . 1119 

14.19 Memory and microcode fields. 1122 





















1062 Version "F": 32-bit registers, big-endian, privileges 


14.20 Opcodes. 1125 

14.21 Data initialization. 1158 

14.22 Microcode. 1159 

14.23 Process mode and interrupts . 1190 

14.24 Macrocode example: 4 memcpy’ . 1191 

14.25 Macrocode example: TTY with interrupt. 1194 

14.26 Macrocode example: user and supervisor. 1197 


This version of the CPU is made with 32-bit registers and it is able 
to distinguish between privileged and unprivileged processes: un¬ 
privileged processes can not access directly the I/O devices and can 
not modify some status flags. The opcode remains limited to 8-bit 
width, including the argument represented by registers: because of 
this limitation, there are few macrocode instructions, but enough for 
the demonstration purpose of the project. There are other important 
features worth to mention: the data is accessed in big-endian mode 
and the memory is segmented, distinguishing between code and data 
segments. 


Attachments 

Description 

attachments/xcpu/xcpu-f. v 

TKGate Verilog netlist source file. 













Version "F": 32-bit registers, big-endian, privileges 


1063 


Attachments 

Description 

attachments/xcpu/xcpu-f- 

memcpy.gm 

attachments/xcpu/xcpu-f-tty- 

simple.gm 

attachments/xcpu/xcpu-f-user- 

process.gm 

attachments/xcpu/xcpu-f- 

supervisor-and-user.gm 

TKGate microcode and 

macrocode alternative source 
files. 

attachments/xcpu/xcpu-f-terminal. 

vpd.tcl 

TCL/Tk script related to the termi¬ 
nal module TTY. 







1064 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.2. Simple CPU, version “F”. 








































































































































































































































































































































Version "F": 32-bit registers, big-endian, privileges 


1065 


14.1 General purpose modules 

The following figures show some general purpose modules. Some 
of them already appeared in previous versions of the project, with or 
without modifications. 


1066 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.3. Module RANK32 and submodules: rank reduction 
and sign extension. 



F 
































































































Version "F": 32-bit registers, big-endian, privileges 


1067 


Figure 14.4. Modules Dn. 


p > 


Ck > 


D > 


C > 



Q Q 
















































































































































1068 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.5. Modules DHn. 


D 

V 



Q 

































































































Version "F": 32-bit registers, big-endian, privileges 


1069 


Figure 14.6. Modules Fn. A module Fn , provided that the input 
Ti is asserted, returns the count of the impulses received at the 
Ck input. 



A A 

C C 


14.2 Addition modules 

This version of the simple CPU works with 32-bit registers and 
ALU. The ALU, some registers and some other modules, contain an 
addition module for various reasons. For example DA and CA need 
to calculate the real memory address and some registers need to be 
incremented or decremented. To ensure that the additions are made 
as fast as possible, the technique of the carry lookahead is used. 







































































1070 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.7. Module SUM8 : 8-bit addition with carry lookahead. 


































































































































































































































1 + 1 + 1 + \± 1 + 1 + 

G3 P3 C3 G2 P2 



C4 

P4 

G4 


C2 

CLH4 

























1072 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.9. Module SUM32. 



Figure 14.10. Module sum32 : it is just a wrapper around the 
module SUM32. 


4+ 32 4+ 32 


A B 

Co sum32 ci 
s 



Co <£- 


A 

V 

/^32 


B 

V 

/^32 



A B 

◄- 

CoO 

•«- 

4 

Co1 SUM32 Ci 


Co 

~ 7 + 

V 


S 


/ 


32 


V 


<Ci 


S 





























































































Version "F": 32-bit registers, big-endian, privileges 


1073 


14.3 Multiple clock lines 

All the previous versions of the simple CPU suffer from clock timing 
problems that sometimes arise with the memory access. With this 
version there is a clock generating seven pulses at different offsets: 
with this method, up to fourteen edge triggers can be selected. 

Figure 14.11. Seven clock signals. 









S'* 

S'* 

s* 

S'* 

S'* 

S'* 

s* 















O 



Oo 



On 


uum 


“L 


clock 0 
clock 1 

clock 2 

clock 3 
clock 4 

clock 5 


J clock 6 


A A A A A A A 


O ^ 

^ ^ ^ ^ ^ ^ ^ 

o o o o o o o 

o o o o o o o 


The clock pulse is produced by the module CLKCLR , described by 
the following figures. 


























































































1074 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.12. Module CLKCLR. 


o t- cm co 




4 to DLY ti 


/ 4 
A 

DLY 


10 DLY t 1 


to DLY t 1 


to DLY t 1 


to DLY t 1 


to DLY t 1 


to DLY t 1 


PD- 




4 

/-► 

DLY 

CLKCLR 

Ck 


Rst 

Clr 




=o 


-> Clr 


As it is for the previous version of the simple CPU, the clock gener¬ 
ator is started by a single shot (the module onejup ), represented on 
the left of the figure by a red ‘stair’. Then the modules DLY are sim¬ 
ple delay lines, made of non-inverting buffers. To tune the frequency, 
the delay lines can be adapted with the input value DLY : zero repre¬ 
sents the maximum frequency (the shortest delay), 15 produces the 
minimum frequency (the longest delay). As for the previous clock 
versions, the clear line (Clr output) is to be coordinated with the 
clock. 


































































Version "F": 32-bit registers, big-endian, privileges 


1075 


Listing 14.13. Module onejup , used to start the oscillation inside 
the module CLKCLR . 

module one_up #(.W(1000)) (Z); 

output Z; 
reg Z; 

initial 

begin 

Z = 1'bO; 

$tkg$wait(W); 

Z = l'bl; 
end 

endmodule 




1076 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.14. Module DLY. 

»>-— 


1 >—> 


!>->- 


£>—O 


1>-^ 


i> —l> 


1>—> 


£>-> 


1>—D>- 


->—[>—>- 


{>—D> 


!>->- 


£>-> 


!>->- 


1>—> 





GO 

o Kb 
I_I 


/ / 2 


A 

n 


-> tl 


14.4 Bus 

This version of the simple CPU has only two busses: the U bus is the 
usual data bus, having a 32 bits size, whereas the T is a double pur¬ 
pose bus, used to carry the content of all registers and the microcode 

















































































































































Version "F": 32-bit registers, big-endian, privileges 


1077 


control word. In practice: the U bus is used to exchange data, while 
the T bus allows to any component to read any other register, with¬ 
out extra cabling. In fact, the project could have been designed with 
much less external cabling, but extra visible connections are used 
also to show some important dependencies between modules. 

Inside the T bus, T 19h0 is used to carry a copy of the content from 
every register, as it is described by the following table. 

Table 14.15. Tm-.o fields. 


msb 

Isb 

size 

value of: 

msb 

Isb 

size 

value of: 

31 

0 

32 

A 

479 

448 

32 

MD 

63 

32 

32 

B 

511 

480 

32 

IVT 

95 

64 

32 

C 

543 

512 

32 

TMP0 

127 

96 

32 

D 

575 

544 

32 

TMP1 

159 

128 

32 

1 

607 

576 

32 

TMP2 

191 

160 

32 

J 

639 

608 

32 

TMP3 

223 

192 

32 

SP 

671 

640 

32 

TMP4 

255 

224 

32 

FP 

703 

672 

32 

TMP5 

287 

256 

32 

DSO 

719 

704 

16 

IRQ 

319 

288 

32 

DS1 

727 

720 

8 

FL 

351 

320 

32 

CSO 

735 

728 

8 

IOA 

383 

352 

32 

CS1 

767 

736 

32 

CNS 

415 

384 

32 

PC 

783 

768 

16 

CLKC 

447 

416 

32 

SSP 

791 

784 

8 

IR 


For example, the content of the FP register is available from T 255 : 224 . 
The following table shows the lines from bit 867 to bit 999, used to 
carry the functions to be executed by the modules connected to the T 
bus: on the left side there are the connections to the T bus, whereas 
on the right side there are the original partitions from the microcode 
word. Please notice that, for this version of the simple CPU, eight 
lines are used to carry the clear and clock signals; these eight lines 




1078 


Version "F": 32-bit registers, big-endian, privileges 


are added to the microcode word itself, without replacing anything 
from the original microcode word. 

Table 14.16. T 998:8 67 fields and fiCW i 23 -.o- 


msb 

Isb 

size 

line description 

msb 

Isb 

msb 

Isb 

size 

line description 

msb 

Isb 

874 

867 

8 

clear and clock 

878 

875 

4 

stop, call, load, return 

3 

0 

945 

944 

2 

CS1 

70 

69 

884 

879 

6 

|jC jump condition 

9 

4 

951 

946 

6 

PC 

76 

71 

895 

885 

11 

pC jump address 

20 

10 

953 

952 

2 

SSP 

78 

77 

906 

896 

11 

ALU 

31 

21 

955 

954 

2 

TMP0 

80 

79 

908 

907 

2 

A 

33 

32 

957 

956 

2 

TMP1 

82 

81 

910 

909 

2 

B 

35 

34 

959 

958 

2 

TMP2 

84 

83 

912 

911 

2 

C 

37 

36 

961 

960 

2 

TMP3 

86 

85 

914 

913 

2 

D 

39 

38 

963 

962 

2 

TMP4 

88 

87 

920 

915 

6 

1 

45 

40 

965 

964 

2 

TMP5 

90 

89 

926 

921 

6 

J 

51 

46 

975 

966 

10 

M 

100 

91 

932 

927 

6 

SP 

57 

52 

978 

976 

3 

IVT 

103 

101 

934 

933 

2 

FP 

59 

58 

981 

979 

3 

IRQ 

106 

104 

937 

935 

3 

DA 

62 

60 

984 

982 

3 

FL 

109 

107 

939 

938 

2 

DS0 

64 

63 

986 

985 

2 

IOA 

111 

110 

941 

940 

2 

DS1 

66 

65 

989 

987 

3 

IOC 

114 

112 

943 

942 

2 

CSO 

68 

67 

998 

990 

9 

CNS 

123 

115 


14.5 Registers: simple and with post-increment 


There are two types of registers, the registers A , B , C, D, FP , 
CSO , CS1,DS0 , DS1, SSP , JMP0, TMP1 , TMP2 , TMPJ, TMP4 , 
TMP5 and /OA are simple registers like the one shown in the fol¬ 
lowing figure, which corresponds to SSP: 







Version "F": 32-bit registers, big-endian, privileges 


1079 


func 



U 


The register is made with a 32-bit D flip-flop (positive edge trig¬ 
gered), connected to a multiplexer that can select from the previous 
flip-flop output or a new input from the U bus. The control lines are 
only two: load (bus-read) and enable (bus-write). The control lines 
(the function) are taken from the T bus (in that case they correspond 
to T 953 : 952 ) and a copy of the register content is also sent to the T bus 

(P 447 : 416 ). 

The registers /, /, SP and PC, can be post-incremented or post- 
decremented. The following figure shows the register PC : 










































1080 


Version "F": 32-bit registers, big-endian, privileges 



In that case the control lines are six: load (bus-read), enable (bus- 
write) and four lines representing a signed increment, from -8 to 
+7. 


Some registers (A, B , /, /, SP, FP, DSO , DS1, CSO , CS7 and 
PC) have an extra output connection (like it appears in the previous 
figure). This is done to connect the register to some other module. As 
already explained in a previous section, every register sends its own 
value to a private channel inside the T bus, where it could be read by 
any other module connected to it. But here these extra connections 
are kept to highlight their purpose. 

14.6 Memory segmentation 

In this version of the simple CPU, the address used to access the 
memory is relative to a ‘segment’. That is: if a program is work¬ 
ing inside a segment located at address 100000i 6 , up to address 
200000 i6, the relative address 123 i 6 is located in memory at the real 
address 100123 i 6 ; moreover, if a program tries to reach the location 














































































Version "F": 32-bit registers, big-endian, privileges 1081 

100001 16 , which corresponds to the real address 200001 16 , an inter¬ 
rupt if fired and the program might be stopped. 

There are two memory segments: data and code. The data segment 
is delimited by the registers DS0 and DS1 , where the former is used 
to point to the start of the segment, whereas the latter should point 
to the address after the end of the segment. For example, if DS0 
and DS1 contains zero (which is the default starting value), the seg¬ 
ment covers the entire memory addressable. The code segment, rep¬ 
resented by the registers CS0 and CS1 , works the same way. 

When accessing the memory, through the module M, it must be 
specified if the access is relative to the data segment, or the code seg¬ 
ment. When loading the opcode inside the instruction register (. IR ) 
and the arguments following the opcode, the code segment is taken 
into consideration, whereas, for any other access, the data segment 
is in control. 

The module DA ( data address ) is responsible for calculating the real 
address used for the data segment. It is connected to the registers /, 
/, SP and FP : any data segment access requires to have loaded, at 
least, an address inside one of these registers. 

The module CA (code address) is used to calculate the real address 
for the code segment and depends from the register PC. 



1082 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.19. Connection with modules DA and CA, to calculate 
and validate the requested addresses, for data and code segments. 


CM 

CO 

M 


$ t 

t $ 

t t 

t t 

* * 

♦ * 

* 

=> 1- 

1 

1- => 

J 

—> 

1 

0- dS 

C/D 

n 

=> 

FP 

CL 

LL 

=> i- 

DSO 

O 

CO 

0 

1- => 
DS1 

CO 

o 

=> 1- 

.o DA 

COCO CL CL b: 

QD LL CO - 3 <D 


\ 

CM \ 
CO 


\ 


CM 


Ll 


J+ 


\| 

CM 

CO 


t 

K 


\ 

CM \ 
CO 





♦ 

♦ 

t 

i t 





T U 

PC 

PC 

U T 

cso 

cso 

T U 

CS1 

CS1 

/ 

CS1 

CA 

CSO PC err A 

/ 

CM 

CO 

-K _ 


* 

CO 

l>0 

^Ep2l 

_ It 


t 

* t t 









14.7 Module "DA" 

The module DA is used to calculate the real memory address for 
something located in the data segment. The real memory address is 
calculated adding the value contained inside the registers DSO and 
J: the former is used to specify the begin of the data segment and 
the latter as an index from the selected relative address. The relative 
address used as input to the DA module might come from the address 
registers, /, /, SP and FP , with the exception that if the J input is 
selected, J itself is not added again. 
















































Version "F": 32-bit registers, big-endian, privileges 


1083 


Figure 14.20. Module DA. 



The module output is A {address) and a check is made to verify if the 
real memory address is contained before the value reported by regis¬ 
ter DS1 . If the calculated real address is outside the allowed memory 
segment, the output err is asserted. This version of the DA module 
does not prevent the access outside the allowed memory segment. 

14.8 Module "CA" 

The module CA is used to calculate the real memory address for 
the code. The real memory address is calculated adding the value 
contained inside the registers CSO and PC. 
































































1084 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.21. Module CA. 



A 

The module output is A (address) and a check is made to verify if the 
real memory address is contained before the value reported by regis¬ 
ter CS1 . If the calculated real address is outside the allowed memory 
segment, the output err is asserted. This version of the CA module 
does not prevent the access outside the allowed memory segment. 

14.9 Modules "M" and "RAM" 

The module M is responsible for all memory access, selecting a real 
address from the DA module or from the CA module. The memory 
is organized with 8-bit blocks, but the M module receives the re¬ 
quest to access a certain byte inside a particular word that starts at a 
particular address. For example, it might be requested to access the 
byte two of a 32-bit word, located at the address 00000010i 6 : 





































Version "F": 32-bit registers, big-endian, privileges 


1085 



32-bit word 

B B B B 

3 2 10 

t 

As it should be visible in the figure, the byte that the module M 
will access is located at address 00000011 1 6 . To obtain this result, 
the module requires to know the width of the data requested (the 
rank) and the byte position inside the requested word. The rank is a 
number —from zero to three— that refers to a rank from one byte 
to four bytes; the byte position is a number —from zero to three— 
that refers to a byte from the least significant byte (LSB) to the most 
significant one (MSB). The module M subtracts the byte position 
from the rank and then adds the result to the real address. Following 
the example shown above, it gets a value of 3 for the rank and a value 
of 2 for the byte position: 3-2=1; 00000010i 6 +l =00000011 1 6 - 










1086 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.23. Module M. 



\% 999 /ft 32 

T U 


T 

M 

U 

oe 

md ma we CA DA IN 

IR 


I 4 - /|^ 8/^32 1" 4 /(* 32/|*32/f 4 8 






























































































Version "F": 32-bit registers, big-endian, privileges 1087 

The calculated address is stored inside a 32-bit D flip-flop at the 
clock6 edge: 


Ci 

Ci 

ci 

ci 

Ci 

ci 

ci 

s - 

s - 

O - 

s - 

s - 

s - 

s - 

Ci 

ci 

ci 

ci 

ci 

ci 

ci 




*r 




O 


to 

Oo 



on 




Y Y Y Y Y Y Y 


A A A A A A A 


o ^ <n ^ "n 

^ 

<o <o <o <o 

o o o o o o o 

7j 7j 7j 7j 7j 7j 7j 


clock 0 
clock 1 

clock 2 

clock 3 
clock 4 


clock 5 
\ clock 6 


the memory address is saved at this time 


The memory is read starting from the clock6 edge and it is written 
starting from the clockO edge: 
























































































1088 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.25. Read and write access timing. 


Ci 

Ci 


ci 

O 

O 

O 

o' 


o' 

o' 

o' 

o' 

o' 

ci 

ci 

O 

o 

O 

o 

O 








o 

^-4 

Nj 

Oo 


Or, 

ON 


o 

<*r 


yyyyyyyy 


“L 


A A A A A A A 


rn ^ ir> VO 


<0 


<0 


<0 


<0 


<0 


O 


<0 


clock 0 
clock 1 

clock 2 

clock 3 
clock 4 

clock 5 


J clock 6 


the memory address is available at this time 


the read access begins here 


the write access begins here 


When something is read from the memory, the output is collected 
by the modules MD {memory data) or IR {instruction register). It 
depends on the type of data selected: the code is to be received by 
the IR register, whereas the other data is to be received by the MD 
register. When something is to be written to the memory, the byte is 
taken directly from the U bus, selecting the byte that is to be writ¬ 
ten. The module M has also an additional output IN that is used to 
connect the module IVT : this is done to emphasize the transition of 
a software interrupt number, read from the memory and received by 
the IVT module, which translates it into a pointer to the IVT table 
in memory. 



























































































Version "F": 32-bit registers, big-endian, privileges 


1089 


Figure 14.26. Module sum2, used to calculate the byte offset 
from the requested address, knowing the byte rank and the byte 
relative position. 




The module RAM contains the RAM memory, to hide the fact that 
it is made of two memory components, because the TKGate version 
used to build and simulate this project is not able to handle memory 
components with more than 31 bits for the address. 


Figure 14.27. Module RAM. 



-O D 


oe> 

































































1090 

14.10 Module "IR" 


Version "F": 32-bit registers, big-endian, privileges 


The module IR is an 8-bit register —similar to the other registers— 
that is embedded inside the module M. The IR register never writes 
to the U bus and only a single line is used to control the register-load 
action. The register IR is updated at the clock2 edge and its content 
is sent directly to the CTRL module. 


Figure 14.28. The register IR is updated at the clock2 edge. 



the IR register is updated here 





























































































Version "F": 32-bit registers, big-endian, privileges 


1091 


Figure 14.29. The IR register. 


clear and clock 



14.11 Module "MD" 


The module MD is a register used to store a word, while it is read 
from the memory, byte after byte. The module requires to know 
which byte is readed from the expected word that is to be obtained. 
For example, when reading the byte two of a 32-bit word, the second 
8-bit D flip-flop on the left is used to store the data. 
































1092 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.30. Module MD. 



The first 8-bit register on the right is different, because it is used a 
D latch instead, so that it holds the data when the clock is high, but 
the data received is already available on the output. The read access 
to the memory is done starting from the most significant byte, ending 
to the least significant one. That is: when reading the least significant 
byte all the other bytes are already available inside the other D flip- 
flop and the whole word is usually written to the U bus. 

When writing to the U bus, the module MD requires to know the 
rank and if the value is signed or unsigned, so that the module 






















































































Version "F": 32-bit registers, big-endian, privileges 

RANK32 is able to fix the final value that is sent to the bus. 


1093 


The clock signal used to update and hold the data received is clock4 , 
just like the other registers, but should be clear that when writing the 
U bus, the data is ready before the clock4 edge, because the least 
significant byte is holded by the 8-bit D latch on the right. 

14.12 Module "IRQ" 

The module IRQ is the same as the previous version, except that it 
is able to handle eight different signals. 


Figure 14.31. Module IRQ. 



Another difference from the previous version of the module IRQ is 
that the selected IRQ (from the priority selection) is sent without 


















































































1094 


Version "F": 32-bit registers, big-endian, privileges 


conversions to the IVT module (it is the IVT module that converts 
what is necessary). 


Figure 14.32. Module irq_priority. 

priority 0 


irq_mix 


>- 


irq_mix 

irq_priority 

irq_selected 


irq_set 



8 




priority 1 


priority 2 


priority 3 


priority 4 


3Z> 


<>—© 


irq_selected 


irq set 


^ irq_set 












































































Version "F": 32-bit registers, big-endian, privileges 


1095 


Figure 14.33. Module irq_register . 


irq_mix 

irq_priority 

irq_selected 


irq_set 





Q D 

D1 


8 


IRQ 

V 


/ 8 


Ncom'tnaii-o 




Q D 

D1 


£ 


Q D 

D1 


1 


Q 

P 

D 

Q 

D1 

- Ck 

C 


J? 


Q D 

D1 


-vicnai^coiNO-io 


J? 


Q D 

D1 




Q D 

D1 


J? 


p 

Q D 

D1 


-<c 


14.13 Module "IVT" 

The IVT module is used to store the IVT (interrupt vector table) 
location and to calculate an address inside that table, when receiving 
an interrupt. The IVT table address is stored inside the 32-bit D flip- 
flop on the left; when receiving an interrupt from the int input line, 
or from the irq input line, the interrupt number is multiplied by four 
and added to the IVT table address: the resulting address available 
on the U bus, if writing on it is enabled, corresponds to the element 
of the IVT table that should contain a function address to process the 
interrupt received. 

The interrupt is multiplied by four because each memory address 
occupies 32 bits (four bytes), consequently, every element of the 




























































































Version "F": 32-bit registers, big-endian, privileges 


1096 

IVT table is 32-bit long. 
Figure 14.34. Module IVT. 


- irq_to_int- 




hardware interrupt: 00001... 


00000000 ■ 
00000001 ■ 
00000010 - 
00000100 - 
00001000 - 
00010000 - 
00100000 - 
01000000 - 
10000000 - 


~> 00001000 
-> 00001000 
~> 00001001 
-> 00001010 
-> 00001011 
-> 00001100 
-> 00001101 
~> 00001110 
~> 00001111 


interrupt 

number 


D32 
Q - Ck 



A 


V 

d 


T : 


sir il * 


Co sum32 Ci 


{£999 /|{£32 


T 

U 


IVT 

int irq 

/ 

*8 J^8 


7^32- 


V- 


198:512 
511:480 


' 


clear and clock 


7 ^- <> I 


The IRQ numbers are converted into interrupt numbers, adding the 
fixed value eight (1000 2 ). That is: IRQ 0 becomes INT 8, IRQ 1 
becomes INT 9,... IRQ 7 becomes INT 15. 


14.14 Module "ALU 


The module ALU is similar to the previous version, with the excep¬ 
tion that 32 bits are used. Every operation that results on a value to 
be written in the U bus requires to specify the rank and if it is signed 
or not: the module RANK32 does the necessary adaptations and the 
flags carry, negative and overflow are updated consequently. 

The ALU includes the module SR32 that should be used to get a 
zero or -1 result, but it is not much useful because there is already 

















































































Version "F": 32-bit registers, big-endian, privileges 

the module CNS that can do it better. 


1097 


With the module FLSR the ALU can modify the status register 
(FL), without hardware limitations: it is the microcode to establish 
if such modifications can be done. 

Figure 14.35. Module ALU. 





























































































































1098 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.36. Module SR, used to generate the value zero or -1 
(FFFFFFFFi 6 ). 


T3 -< 


Figure 14.37. Module LOGIC32 : bitwise boolean logic. 




/^32 ^32 



F 




























































Version "F": 32-bit registers, big-endian, privileges 


1099 


Figure 14.38. Module AS32 : addition and subtraction. 


carry out 
borrow out 


x 

V 


Y 

V 


Co - O- 


V < / / 

overflow 


V 32 



subtract 

0 



1 


^- 1 use_carry 

- 




/ / 32 


A 

B 

CoO 


Col 

SUM32 Ci 

Co 


V 

s 


u 


X 32 

X+32 

X 

Y 

f 


Co AS32 

Ci 

V 


F 



* 


32 


2 


-<f 


-<Ci 

carry in 
borrow in 


V 

F 

























1100 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.39. Module SHL32 : any kind of binary shift left. 


Co 


4 

^ Z 


< - 

/ 

-V" 1( — 

7 4 


X 

V 


/ 32 


I I 

o 
o 
CO 


CO 


2 

A 

1 

Pd A 

0 

% 

91 A 

*- 

% 

8 

3 


2 

os] 

1 

ZZ A 

0 

- ni 


31 


32 




<t 


-<Ci 



V 


F 
































Version "F": 32-bit registers, big-endian, privileges 


1101 


Figure 14.40. Module LSHR32 : logic shift right. 

































































1102 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.41. Module ASHR32 : arithmetic shift right. 


r>- 



2 

7 ^ 


PP, 


X 

V 




32 


Co 
























































Version "F": 32-bit registers, big-endian, privileges 


1103 


Figure 14.42. Module ROTL32 : rotation left. 


x 

V 



/ 


/ 


32 


F 


4+ 32 

X 

ROTL32 r £- 
F _ 

4* 32 



























1104 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.43. Module ROTR32 : rotation right. 


r>- 



2 

7 ^ 


PP 


’A- 


X 

V 


32 


/ 


/ 


CD 


00 


/ ~7 / ~7 / 

(/ 7 / 


/ 


/ 


V 


32 



















































Version "F": 32-bit registers, big-endian, privileges 


1105 


Figure 14.44. Module FLSR , used to change the flags inside the 
FL register. The module FLSR allows to change any flags, but 
it is checked inside the microcode if it is allowed. 


FLi 

V 




FL7 = S, supervisor process 
FL7:4 can be changed only by a supervisor process (as defined inside the microcode) 


14.15 Module TL A 


Flags are more sophisticated inside this version of the simple CPU, 
because half of the flags can be modified only by a supervisor pro¬ 
cess. Here are the current flags meaning: 








































1106 


Version "F": 32-bit registers, big-endian, privileges 


FL FL FL FL FL FL FL FL 

7 6 5 4 3 2 1 0 


p \ 

s 

v J 

d \ 

T 

p \ 

R 

v J 

/ \ 

I 

v J 

P \ 

V 

v J 

P \ 

N 

v J 

p \ 

Z 

L J 

p \ 

c 

L J 


supervisor 

transition (user —> supervisor) 

IRQ pending 

IRQ enabled 


carry or borrow 


zero 


negative 
overflow 


The figure shows the flags FL 7:4 emphasized, because these flags 
can be modified only when the ‘supervisor’ flag is already active. A 
supervisor process can decide to lose its own privileges, but then it 
can not gain them again, except when an interrupt is processed: it is 
supposed that the interrupt procedures listed inside the IVT table are 
sure enough to be executed with privileges. 


The FL register is different from the previous version, because it 
should not allow to gain privileges when not allowed. The register 
can be loaded from the U bus or from the ALU module, but when 
loading from the bus, it is possible to chose to update only the zero 
and negative flags. In other words, the FL can: keep the value stored, 
load a new value from the bus, update the zero and negative flags 
from the value available in the bus, load a new value from the ALU. 


When loading a new value from the bus, the register can accept to 
modify the bits FL 7:4 only if the supervisor flag is already active. 

The bit FL 5 is never stored, because it just comes from the IRQ 
module and it represent a pending IRQ request, which might or 
might not be processed (it depends on the flag FL 4 ). 


















Version "F": 32-bit registers, big-endian, privileges 


1107 


Figure 14.46. Module FL. 


clear and clock 


99?— T 


E 719:0 

727:71 


FLO = C, carry 
FL1 = Z, zero 
FL2 = N, negative 
FL3 = V, overflow 
FL4 = I, IRQ enabled 
FL5 = R, IRQ requested 
FL6 = T, transition (bigger stack after interrupt) 

FL7 = S, supervisor process 

FL7:4 can be changed only by a supervisor process 


l 27 


+ 8 , 


FLo 

FLi R 


FL 

T 

U 


J^999^ 


negative from the bus 

_£_ m n 

' 2 

• — p — ,r ° m the bus 


1 

0 


previous_other_flag: 


64 




FLo^4. 


FL7:4 can be changed only 
by a supervisor process 


previous_carry 


update_from_the_bus 


When reset, the system 
must start in supervisor 
mode: this is the 
supervisor flag. 


D1 

ndQ = ck 


□r 




JV 


JT 


? Q 






0 

















































































« 


1108 

14.16 Module "TTY" 


Version "F": 32-bit registers, big-endian, privileges 


The TTY module is almost the same as the previous version, replac¬ 
ing the old module DR8 with a D flip-flop with external multiplexer. 
The module TTY is a textual screen-keyboard terminal interface. All 
the details about the module functionality should be found at some 
previous versions description. 

Figure 14.47. Module TTY. 




S_DATA 





S_REQ 



S_ACK 

terminal 


K_DATA 



K_REQ 



K_ACK 

CLR 




















































































































Version "F": 32-bit registers, big-endian, privileges 

Listing 14.48. Module terminal : Verilog code. 

module terminal(K_DATA, K_REQ, K_ACK, 

S_DATA, S_REQ, S_ACK, CLR) 

output K_ACK; 
output S_ACK; 
output [7:0] K_DATA; 
input [7:0] S_DATA; 
input K_REQ; 
input S_REQ; 
input CLR; 
reg k_ready; 
reg [7:0] key; 
reg s_ready; 

initial 
begin 

k_ready = 0; 
s_ready = 0; 
key = 0; 
end 

always 
begin 

@(posedge CLR) 
k_ready = 0; 
s_ready = 0; 
key = 0; 
end 



1 


Version "F": 32-bit registers, big-endian, privileges 


initial $tkg$post("TERMINAL" , "%m"); 

always 

begin 

@ (posedge K_REQ); 

# 5; 

key = $tkg$recv("%m.KD"); 

# 5; 

k_ready = l'bl; 

# 5; 

@ (negedge K_REQ); 

# 5; 

k_ready = 1'bO; 
end 

always 

begin 

@(posedge S_REQ); 

# 5; 

$tkg$send("%m.SD",S_DATA); 

# 5; 

s_ready = l'bl; 

# 5; 

@(negedge S_REQ); 

# 5; 

s_ready = 1'bO; 
end 

assign S_ACK = s_ready; 




Version "F": 32-bit registers, big-endian, privileges 


1111 


assign K_DATA = key; 
assign K_ACK = k_ready; 

endmodule 


Listing 14.49. File ‘share/tkgate/vpd/terminal. tel’ for 

TCL interface. _ 

image create bitmap txteurs -file "$bd/txtcurs.b" 

VPD::register TERMINAL 
VPD::allow TERMINAL::post 
VPD::allow TERMINAL::data 

namespace eval TERMINAL { 

# Public variables declarations: the variables $terminal_... 

# are arrays of which only the element $n is used; 

# that element identifies uniquely the working interface instance. 

variable terminal_w 
variable terminal_pos 

# 

variable KD 

# Function requested by TKGate to create the interface. 

proc post {n} { 

variable terminal_w 
variable terminal_pos 

# Create the window and save the object element in a $terminal_w array element. 

set terminal_w($n) [VPD::createWindow "TERMINAL $n" -shutdowncommand "TERMINAL::unpost $n" ] 

# For convenience, copy the object reference inside the local 

# variable $w; then, the variable $w will be used as a reference to the object. 

set w $terminal_w($n) 
text $w.txt -state disabled 
pack $w.txt 

# Put the cursor at the end of the displayed text. 

$w.txt image create end -image txteurs 

# Bind the keyboard input, related to the object represented by 

# $terminal_w ($n), to the function sendChar. 

bind $w <KeyPress> "TERMINAL::sendChar $n \"%A\"" 

# Open a reading channel, named «SD» (screen data), 

# and associate it to the function «data»; moreover, open a 

# writing channel, named «KD» (keyboard data). 

if {[info exists ::tkgate_islnitialized]} { 

VPD::outsignal $n.KD TERMINAL::KD($n) 

VPD::insignal $n.SD -command "TERMINAL::data $n" -format %d 

} 

# Reset the character count, used to count the characters displayed 

# on screen. 

set terminal_pos($n) 0 





1112 


Version "F": 32-bit registers, big-endian, privileges 


} 

# Function that receives the typing and put It Into the 

# channel «KD», related to the current Interface Instance. 

proc sendChar {n key} { 
variable KD 

if { [string length $key ] == 1 } { 
binary scan $key c c 
set TERMINAL::KD($n) $c 

} 

} 

# Function that TKGate requires to destroy the Interface. 

proc unpost {n} { 

variable terminal_w 
variable terminal_pos 
destroy $terminal_w($n) 
destroy $terminal_pos($n) 
unset terminal_w($n) 
unset terminal_pos($n) 

} 

# Function used to get the data to display on screen. 

proc data {n c} { 

variable terminal_w 
variable terminal_pos 

# For convenience, copy the object reference representing the 

# Interface, Inside the variable $w. 

set w $terminal_w($n) 
catch { 

# The variable $c contains the character to display. 

if { $C == 7 } { 

# BEL 

bell 

return 

} elseif { $c == 127 | | $c == 8 } { 

# DEL I BS 

if { $terminal_pos($n) > 0 } { 

# Delete the last displayed character, but only If the 

# characters counter Is greater than zero, otherwise 

# the cursor would disappear and the next characters 

# would be located In an Invisible screen area. 

$w.txt configure -state normal 
$w.txt delete "end - 3 chars" 

$w.txt see end 

$w.txt configure -state disabled 

set terminal_pos($n) [expr {$terminal_pos($n) - l}] 

} 

return 

} elseif { $c == 13 } { 

# Convert CR to LF. 

set c 10 

} 

# Convert the character number Into a visible symbol. 

set x [format %c $c] 



Version "F": 32-bit registers, big-endian, privileges 


1113 


# Display the symbol . 

$w.txt configure -state normal 
$w.txt insert "end - 2 chars" $x 
$w.txt see end 

$w.txt configure -state disabled 

# Update the displayed characters counter. 

set terminal_pos($n) [expr {$terminal_pos($n) + l}] 

} 

} 

} 


14.17 Module "HDD" 

The HDD module is similar to the previous version: the address is 
now specified with a single 32-bit request and only four virtual units 
are available. All the details about the module functionality should 
be found at some previous versions description. 



1114 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.50. Module HDD. 


T 



Listing 14.51. Verilog code describing the module hd. 

module hd(DRIVE, SECTOR, BYTE, WRITE, DATA_IN, 
DATA_OUT, REQ, ACK, CLR); 
input [1:0] DRIVE; 
input WRITE, REQ, CLR; 

















































































































Version "F": 32-bit registers, big-endian, privileges 


1115 


input [19:0] SECTOR; 
input [9:0] BYTE; 
input [7:0] DATA_IN; 
output [7:0] DATA_OUT; 
output ACK; 

// 

integer _data_out; 
integer _ack; 

// 


reg [7:0] buffer[0:1023]; 
reg [8*24-1:0] filename = 

// 


integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

integer 

// 


i; 

sector_8; 
sector_7 ; 
sector_6; 
sector_5; 
sector_4 ; 
sector_3; 
sector_2; 
sector_l ; 
sector_0; 
x; 


n hd0_sector_000000000.mem"; 


initial 

begin 

for (i=0; i<1024; i=i+l) 
begin 

// 

// Initial buffer reset with 00. 

// 



1116 


Version "F": 32-bit registers, big-endian, privileges 




Version "F": 32-bit registers, big-endian, privileges 


1117 


X = x /10; 
sector_2 = x%10; 
x = x /10; 
sector_3 - x%10; 
x = x /10; 
sector_4 - x%10; 
x = x /10; 
sector_5 = x%10; 
x = x /10; 
sector_6 = x%10; 
x = x /10; 
sector_7 - x%10; 
x = x /10; 
sector_8 = x%10; 

// 

// The string starts from the right to the 
// left! 

// 


filename[12*8+7 

: 12* 

8] 

= sector 

_8 

+ 

8'd48; 

filename[11*8+7 

: 11* 

8] 

= sector 

_7 

+ 

• s. 

00 

00 

filename[10*8+7 

: 10* 

8] 

= sector 

_6 

+ 

• s. 

00 

00 

filename[9*8+7: 

9*8] 

= 

sector_5 

+ 

8' 

d4 8; 

filename[8*8+7: 

8*8] 

= 

sector_4 

+ 

8' 

d4 8; 

filename[7*8+7: 

7*8] 

= 

sector_3 

+ 

8' 

d4 8; 

filename[6*8+7: 

6*8] 

= 

sector_2 

+ 

8' 

d4 8; 

filename[5*8+7: 

5*8] 

= 

sector_l 

+ 

8' 

d4 8; 

filename[4*8+7: 

4*8] 

= 

sector_0 

+ 

8' 

d4 8; 

// 







filename[21*8+7 

: 21* 

8] 

= DRIVE • 

+ 8 

' d4 8; 


// 

if (WRITE) 



1118 


Version "F": 32-bit registers, big-endian, privileges 


begin 

// 

// Put data inside the buffer. 

// 

buffer[BYTE] = DATA_IN; 

// 

// Save the buffer to disk. 

// Please remember that $writememh() must 
// be enabled inside Tkgate configuration! 
// 

$writememh(filename, buffer); 

// 

// Return the same data read. 

// 

_data_out = buffer[BYTE]; 
end 
else 
begin 

// 

// Get data from disk to the buffer. 

// 

$readmemh(filename, buffer); 

// 

// Return the data required. 

// 

_data_out = buffer[BYTE]; 
end 

// 

// Acknowledge. 

// 

_ack = 1; 



Version "F": 32-bit registers, big-endian, privileges 


1119 


// 

// Wait the end of request (the negative edge) 
// before restarting the loop. 

// 

@(negedge REQ); 

# 10 ; 

// 

// Now become ready again. 

// 

_ack = 0; 
end 

// 

assign DATA_0UT = _data_out; 
assign ACK = _ack; 

// 

endmodule 


14.18 Module "CTRL" 

The module CTRL is more complex than the previous version of 
this experimental project; apart the clock generator that is described 
in a previous section, there is also a new register, fiRA , that can be 
used to save a return address inside the microcode (the microcode 
might contain calls and returns, provided that they are not nested). 
However, the current microcode implementation does not use inter¬ 
nal calls. 



1120 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.52. Module CTRL. 



The microprogram counter ( fiPC ) is a 11-bit D flip-flop with an 
adder that increments the counter value when no load is requested. 







































































































































Version "F": 32-bit registers, big-endian, privileges 


1121 


The adder that appears in the following figure is just a reduced mod¬ 
ule of the SUM32 : there are many unused output and the B input is 
also zeroed, because it is used only to increment by one, through the 
carry-in. 

Figure 14.53. Module /iPC. 


D 

V 



A 

C 


The register /iRA {microcode address ) is similar to the micropro¬ 
gram counter, but this time the loaded value is stored incremented, 
because when the current microcode address is loaded, the return 
address to be saved should be the next address. 































1122 


Version "F": 32-bit registers, big-endian, privileges 


Figure 14.54. Module fiRA. 


D 

V 



A 

C 


14.19 Memory and microcode fields 

The memories for this version of the project are described by the 
following lines of TKGate code. In this version of the project, every 
component has only the required functions and so the overall control 
lines are less than before. 






























Version "F": 32-bit registers, big-endian, privileges 


1123 


Listing 14.55. Memory banks description for TKGate. 


map 

bank[9:0] 

Ctrl.map; 

microcode 

bank[31:0] 

Ctrl.microO; 

microcode 

bank[63:32] 

Ctrl.micro1; 

microcode 

bank [95:64] 

Ctrl.micro2; 

microcode 

bank[123:96] 

Ctrl.micro3; 

macrocode 

bank[8:0] 

ram.ramO; 


Listing 14.56. Fields of the microcode word, for TKGate. 


field CTRL[3:0] 
field JUMP[9:4] 


field ADDR[20:10] 
field ALU[31:21] 


field Ar[33:32] 
field Br [35:34] 
field Cr[37:36] 


= {nop=0x0, stop=0xl, call=0x2, load=0x4, 
return=0x8}; 

= {carry_t=0x00, zero_t=0x01, negative_t=0x02, 
overflow_t=0x03, irq_enabled_t=0x04 , 
irq_requested_t=0x05, transition_t = 0x0 6, 
supervisor_t=0x07, carry_f=0x0 8 , zero_f=0x0 9, 
negative_f=0x0A, overflow_f=0x0B, 
irq_enabled_f=0x0C, irq_requested_f=0x0D, 
transition_f=0x0E, supervisor_f=0x0F, 
conditiona1=0x10, unconditiona1=0x2 0} ; 

= {start=0x0}; 

= {rank8=0x000, rankl6=0x001, rank24=0x002, 

rank32=0x003, unsigned=0x000, signed=0x0 0 4 , 
set0=0x000, setl=0x008, equal=0x040, and=0x048, 
or=0x050, xor=0x058, nxor=0x060, nor=0x068, 
nand=0x070, not=0x078, add=0x080, sub=0x088, 
addc=0x090, subb=0x098, lshl=0x0C0, lshcl=0x0C8, 
lshr=0xl00, lshcr=0xl08, ashl=0x0C0, ashr=0xl40, 
rot1=0x18 0, rotr=0xlC0 , carry0 = 0x2 0 0, 
carry1=0x240, zero0=0x208, zero1=248, 
negative0=0x210, negative1=0x250, 
overfIow0 = 0x218, overf1owl = 0x258, irqen0 = 0x22 0, 
irqen1 = 0x2 60, irqreq0 = 0x22 8, irqreql = 0x2 68, 
transition0 = 0x230, transition1 = 0x27 0, 
supervisor0 = 0x238, supervisor1 = 0x27 8, 
enable=0x400}; 

= {load=0xl, enable=0x2}; 

{load=0xl, enable=0x2}; 

{load=0xl, enable=0x2}; 





1124 


Version "F": 32-bit registers, big-endian, privileges 


field 

Dr[39:38] 

= 

{load=0xl, enable=0x2}; 

field 

Ir[41:40] 

= 

{load=0xl, enable=0x2}; 

field 

Ii[4 5:42] 

= 

{zero=0x0}; 

field 

Jr [47:4 6] 

= 

{load=0xl, enable=0x2}; 

field 

Ji [51:48] 

= 

{zero=0x0}; 

field 

SPr[53:52] 

= 

{load=0xl, enable=0x2}; 

field 

SPi [57:54] 

= 

{zero=0x0}; 

field 

FPr[59:58] 

= 

{load=0xl, enable=0x2}; 

field 

DA[62:60] 

= 

{enable=0xl, i=0x0, j=0x2, sp=0x4, fp=0x6}; 

field 

DSO[64:63] 

= 

{load=0xl, enable=0x2}; 

field 

DS1[66:65] 

= 

{load=0xl, enable=0x2}; 

field 

CSO [68:67] 

= 

{load=0xl, enable=0x2}; 

field 

CS1 [70:69] 

= 

{load=0xl, enable=0x2}; 

field 

PCr[72:71] 

= 

{load=0xl, enable=0x2}; 

field 

PCi[76:73] 

= 

{zero=0x0}; 

field 

SSP [78:77] 

= 

{load=0xl, enable=0x2}; 

field 

TMPO[80:79] 

= 

{load=0xl, enable=0x2}; 

field 

TMP1[82:81] 

= 

{load=0xl, enable=0x2}; 

field 

TMP2[84:83] 

= 

{load=0xl, enable=0x2}; 

field 

TMP3[86:85] 

= 

{load=0xl, enable=0x2}; 

field 

TMP4[88:87] 

= 

{load=0xl, enable=0x2}; 

field 

TMP5[90:89] 

= 

{load=0xl, enable=0x2}; 

field 

M [100:91] 

= 

{rank8=0x000, rankl6=0x001 , rank24=0x002, 




rank32=0x003, byte0=0x000 , byte1=0x004, 

byte2 = 0x0 0 8, byte3 = 0x0 0C, 

data=0x000, code=0x010, ram_oe=0x020, 

ram_we=0x0 4 0, md_enable=0x0 8 0 , unsigned=0x0 0 0, 
signed=0xl00 , ir_load=0x200}; 

field 

IVT[103:101] 

= 

{load=0xl, enable=0x2, irq=0x0, int=0x4}; 

field 

IRQ[106:104] 

= 

{mask_load=0xl^ mask_enable=0x2 , irq_done=0x4} ; 

field 

FL[109:107] 

= 

{enable=0xl, load_bus = 0x2 , 
update_bus=0x4, load_alu=0x6}; 

field 

I0A[111:110] 

= 

{load=0xl, enable=0x2}; 

field 

IOC[114:112] 

= 

{load=0xl, enable=0x2, req=0x4}; 

field 

CNSv[122:115] 

= 

{zero=0x0}; 

field 

CNS[123:123] 

= 

{enable=0xl}; 





Version "F": 32-bit registers, big-endian, privileges 


1125 


14.20 Opcodes 

This version of the simple CPU has a different set of opcodes, be¬ 
cause the overall structure is different from the previous version, but 
the size remains of a single byte. Please notice that all the 256 com¬ 
binations are used and therefore there is no ‘operror’. 

Table 14.57. Opcodes. 

byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 by * e by £ e 



b7 | b6 | b5 | 

Ib4l 

b3 

b2 

| bl | bO 

0x00 00000000 

nop 

0x00 0000.... 

store %, % 

A|B 

A|B|C|D|I|J|SP|FF 

0x10 0001.... 

load %, % 

A|B 

A|B|C|D|I|J|SP|FF 

0x20 00100... 

load8 0|1, (%) 

rank8 

sign 

l|J|SP|FP 

0x28 00101... 

load16 0|1, (%) 

rank16 

sign 

l|J|SP|FP 

0x30 00110... 

load24 0|1, (%) 

rank24 

sign 

l|J|SP|FP 

0x38 00111... 

load32 0|1, (%) 

rank32 

sign 

l|J|SP|FP 


byteO byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 by J e byte by £ e 



b7 | b6 | b5 | b4 | b3 

_Q 

CM 

-Q 

bO 


0x40 0100000. 

load8 0|1, n 

rank8 

sign 

const| 

0x42 0100001. 

load16 0|1, n 

rank16 

sign 

const16 | 

0x44 0100010. 

load24 0|1, n 

rank24 

sign 

const24 

0x46 0100011. 

load32 0|1, n 

rank32 

sign 

const32 | 


byteO byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 by J e byte by jf 


0x48 01001. 

0x50 0101.. 

0x60 011000 

0x64 011001 
0x68 011010 

0x6C 011011 
0x70 OHIO. 

0x78 01111. 

byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 by J e by * e by * e 


0x80 100000. 
0x84 100001. 
0x88 100010. 
0x8C 100011. 
0x90 100100. 
0x94 100101. 
0x98 100110. 
0x9c loom. 


b7 | b6 | b5 | b4 | b3 | b2 

bl | bO 

equal 

rank 

not 

rank 

and 

rank 

nand 

rank 

or 

rank 

nor 

rank 

xor 

rank 

nxor 

rank 


b7 | b6 | b5 | b4 | b3 

b2 

bl | bO 

lea %, (%) 

A|B 

l|J|SP|FP 

swap %, % 

A|B 

A|B|C|D|I|J|SP|FF 

store (%) 

rank8 

l|J|SP|FP 

store (%) 

rank16 

l|J|SP|FP 

store (%) 

rank24 

l|J|SP|FP 

store (%) 

rank32 

l|J|SP|FP 

push % 

A|B|C|D|I|J|SP|FF 

pop % 

A|B|C|D|I|J|SP|FF 






















































1126 


Version "F": 32-bit registers, big-endian, privileges 


byteO byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 by ‘ e byte by ‘ e 


OxAO 

0xA4 

0xA8 

OxAC 

OxBO 

0xB4 

0xB8 

OxBC 


OxCO 

0xC4 

0xC8 

OxCC 

OxDO 

0xD4 


0xD8 

OxDA 

OxDC 

OxDD 

OxDE 

OxEO 

0xE2 


0xE4 
0xE6 
0xE7 
0xE8 
OxFO 
0xF2 
0xF3 
OxF 4 
CxF.B' 


101000 . 

101001 . 

101010. 

101011 . 

101100. 

101101 . 

101110 . 

101111 . 


110000 . 

110001 . 

110010. 

110011 . 

110100. 

110101 . 


b7 | b6 | b5 | b4 | b3 | b2 

bl | bO 

add 

rank 

sub 

rank 

addc 

rank 

subb 

rank 

Ishl 

rank 

Ishr 

rank 

ashl 

rank 

ashr 

rank 


byte 0 


byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 


byte 

10 


byte 

11 


byte 

12 


b7 | b6 | b5 | b4 | b3 | b2 

bl | bO 

rotcl 

rank 

rotcr 

rank 

rotl 

rank 

rotr 

rank 

utrunc 

rank 

strunc 

rank 



byte 0 


byte 1 byte 2 byte 3 byte 4 


b7 | b6 | b5 | b4 | b3 | b2 | bl 

bO 


1101100 . 

clear 

A|B 


1101101 . 

set 

A|B 


11011100 

comp 


11011101 

test 


1101111 . 

flag_c 0|1 

set 


1110000 . 

flag_i 0|1 

set 


1110001 . 

flag_t 0|1 

set 



byte 0 


byte 1 byte 2 byte 3 byte 4 


b7 | b6 | b5 | b4 | b3 | b2 | bl 

bO 


1110010 . 

call (%) 

in 


11100110 

call #ref 

#ref ] 

11100111 

return 


11101 ... 

jump %flag 0|1 #ref | %flag 

TRUE 

#ref | 

1111000 . 

jump (%) 

in 


11110010 

imrl 

mask| 

11110011 

ivtl 

#ref | 

11110100 

int 

int | 

11110101 

iret 



byte 5 byte 6 byte 7 byte 8 byte 9 


byte 

10 


byte 

11 


byte 

12 


byte 5 byte 6 byte 7 byte 8 byte 9 


byte 

10 


byte 

11 


byte 

12 


byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 by J e by * e by £ e 


0xF6 1111011. 

0xF8 1111100. 

b7 | b6 | b5 | b4 | b3 | b2 | bl 

bO 





in n 

A|B 

port 


out n 

A|B 

port 

OxFA 11111010 

memcpy 


#src 

| #dst | 

size 

OxFB 11111011 

store_ssp 





OxFC 11111100 

jump 

#ref 



OxFD 11111101 

jump csO, csl, #ref 

csO 

csl 

#ref 

OxFE 11111110 

jump dsO, dsl 

dsO 

dsl 


OxFF 11111111 

halt 













Version "F": 32-bit registers, big-endian, privileges 


1127 


Table 14.58. Macrocode syntax. 


Macrocode syntax 

Description 

nop 

Not operate. 

store %A|%B^ ^^ 

^ %A | %B | %C | %D | %I | % J | %SP | %FP 

store %src, %dst 

load %A | %B | %C | %D | %I | %J | %SP | %FP, 

^ %A | %B 

load %dst, %src 

Copy the src register con¬ 
tent inside the dst register. 

load8 0, (%I %J %SP %FP ) 

Load an unsigned 8-bit 
value from the memory, 
at the address specified 
by the register that ap¬ 
pears inside parentheses 
plus /, but if the regis¬ 
ter J is specified, no ad¬ 
dition is made to the ad¬ 
dress. The value loaded 
from the memory is stored 
inside the register A . 




1128 


Version "F": 32-bit registers, big-endian, privileges 


Macrocode syntax 

Description 

load8 1, (%I %J %SP %FP) 

Load a signed 8-bit value 
from the memory, at the 
address specified by the 
register that appears inside 
parentheses plus J , but if 
the register J is specified, 
no addition is made to the 
address. The value loaded 
from the memory is stored 
inside the register A . 

loadl6 0 1, (%I %J %SP %FP) 

load24 0 1, (%I %J %SP %FP) 

load32 0 1, (%I %J %SP %FP) 

As above, but loading a 
16, 24 or 32-bit value. 

load8 0 1 , value 

Load the specified value 
as unsigned or signed 8- 
bit, into the A register. 


loadl6 0 1, value 


load2 4 0 1, value 


load32, 0 1 value 


As above, but loading a 
16, 24 or 32-bit value. 




Version "F": 32-bit registers, big-endian, privileges 


1129 


Macrocode syntax 


Description 


lea %A %B, (%I %J %SP %FP) 


Load inside the register 
A or B the address con¬ 
tained inside the register 
in parentheses, plus the 
value of J. But if J was 
specified, it is just loaded 
as it is. 


swap %A %B, ./_> 




(%A %B %C %D %I %J %SP %FP) 


Swap the value of the first 
argument, with the one of 
the second. 


store8 (%I %J %SP %FP) 


storel 6 

(%I 

%J 

%SP 

store24 

(%I 

%J 

%SP 

store32 

(%I 

%J 

%SP 


Store an 8, 16, 24 or 32-bit 
value from the register A , 
to the address specified by 
the register in parentheses. 
If the register is not J , its 
value is added to J to find 
the destination address. 


push %A %B, ,/_> 




;A %B %C %D %I % J %SP %FP 


pop %A %B, 




;A %B %C %D %I % J %SP %FP 


Push or pop the specified 
register. Push means that 
the SP register is decre¬ 
mented by 4 and at the 
memory location that SP 
points, the specified regis¬ 
ter is saved. Pop means to 
read from the address re¬ 
ported by the SP register a 
value that is then stored in¬ 
side the register specified. 




1130 


Version "F": 32-bit registers, big-endian, privileges 


Macrocode syntax 

Description 

equal8 


equall6 

A A , updating the flags. 
The number specify the 

equal24 

rank; the result is sign- 
extended if necessary. 

equal32 


not 8 


not 16 

A ~A, updating the 

flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

not24 

not 32 


and8 


andl 6 

A <— A & B, updating the 
flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

and24 

and32 





Version "F": 32-bit registers, big-endian, privileges 


1131 


Macrocode syntax 

Description 

nand8 

A ~(A & B), updat- 

nandl6 

ing the flags. The number 
specify the rank; the result 

nand2 4 

is sign-extended if neces¬ 
sary. 

nand32 


or8 


orl 6 

A A 1 B, updating the 

flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

or2 4 

or32 


nor8 

A ~(A 1 B ), updat¬ 

norl 6 

ing the flags. The number 
specify the rank; the result 

nor24 

is sign-extended if neces¬ 
sary. 

nor32 





1132 


Version "F": 32-bit registers, big-endian, privileges 


Macrocode syntax 

Description 

xor8 


xorl 6 

A <— A A B, updating the 
flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

xor24 

xor32 


nxor8 

A <— ~(A A B), updat- 

nxorl6 

ing the flags. The number 
specify the rank; the result 

nxor2 4 

is sign-extended if neces¬ 
sary. 

nxor32 


add8 


addl 6 

A <— A + B, updating the 
flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

add2 4 

add32 





Version "F": 32-bit registers, big-endian, privileges 


1133 


Macrocode syntax 

Description 

sub8 


subl 6 

A <— A + B, updating the 
flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

sub24 

sub32 


addc8 

A <— A + B + carry, up- 

addcl6 

dating the flags. The num¬ 
ber specify the rank; the 

addc2 4 

result is sign-extended if 
necessary. 

addc32 


subb8 

A A - B - borrow, up¬ 

subbl6 

dating the flags. The num¬ 
ber specify the rank; the 

subb2 4 

result is sign-extended if 
necessary. 

subb32 





1134 


Version "F": 32-bit registers, big-endian, privileges 


Macrocode syntax 

Description 

lshl8 


lshll6 

A <- A«l, updating the 

lshl2 4 

flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

lshl32 


lshr8 

A lshr A» 1, updat- 

lshrl6 

ing the flags. The number 
specify the rank; the result 

lshr2 4 

is sign-extended if neces¬ 
sary. 

lshr32 


ashl8 


ashll6 

A A«< 1, updating the 
flags. The number specify 
the rank; the result is sign- 
extended if necessary. 

ashl2 4 

ash!32 





Version "F": 32-bit registers, big-endian, privileges 


1135 


Macrocode syntax 

Description 

ashr8 


ashrl6 

A <— A»> 1, updating the 
flags. The number specify 

ashr2 4 

the rank; the result is sign- 
extended if necessary. 

ashr32 


rotcl8 

A rotcl A (rotate left 

rotcll6 

with carry), updating the 
flags. The number specify 

rotcl24 

the rank; the result is sign- 
extended if necessary. 

rotcl32 


rotcr8 

A rotcr A (rotate right 

rotcrl6 

with carry), updating the 
flags. The number specify 

rotcr24 

the rank; the result is sign- 
extended if necessary. 

rotcr32 





1136 


Version "F": 32-bit registers, big-endian, privileges 


Macrocode syntax 

Description 

rotl8 

A <— rotl A (rotate left), 

rot116 

updating the flags. The 
number specify the rank; 

rot12 4 

the result is sign-extended 
if necessary. 

rot132 


rotr8 

A v- rotr A (rotate right), 

rotrl6 

updating the flags. The 
number specify the rank; 

rotr2 4 

the result is sign-extended 
if necessary. 

rotr32 


utrunc8 

Truncate the A value at the 

utruncl6 

rank specified by the num¬ 
ber attached to the name. 

utrunc2 4 

The value is intended to be 
unsigned. 

utrunc32 





Version "F": 32-bit registers, big-endian, privileges 


1137 


Macrocode syntax 

Description 

strunc8 

struncl6 

strunc2 4 

strunc32 

Truncate the A value at the 
rank specified by the num¬ 
ber attached to the name. 
The value is intended to be 
signed. 

clear %A 

set %A %I 

%B 

3 

Set the specified register 
to zero or to -1. 

comp 

Update the flags with the 
result of A-B. 

test 

Update the flags with the 
result of A SlB . 

flag_c 0 

1 

Clear or set the carry flag. 

flag_i 0 

1 

Clear or set the interrupt 
allowed flag: can be used 
only by a supervisor pro¬ 
cess. 

flag_t 0 

1 

Clear or set the transition 
flag: can be used only by a 
supervisor process. 




1138 


Version "F": 32-bit registers, big-endian, privileges 


Macrocode syntax 

Description 

call address 

call f label 

call (%I %J) 

Call a procedure, specified 
by its numerical address, 
label or by registers I and 

J . 

return 

Returns from a procedure 
call: it pops the PC value 
from the stack. 

jump address 

call #label 

j ump (%I % J) 

Jump to the specified des¬ 
tination, unconditionally. 

jump 0 1, 

%carry %borrow %zerOf_» 

%negative %overflow, ^ 

^ address # label 

Jump to the specified des¬ 
tination, if the named flag 
is clear or set. 

imrl n8 

Load the interrupt mask. 

ivtl address flab el 

Load the IVT: interrupt 
vector table. The argu¬ 
ment is the interrupt vec¬ 
tor table start address in 
memory. 




Version "F": 32-bit registers, big-endian, privileges 


1139 


Macrocode syntax 

Description 

int n8 

Software interrupt call: 
some registers are pushed 
onto the stack, depend¬ 
ing on the current process 
privileges. 

iret 

Return from an interrupt, 
restoring the registers pre¬ 
viously pushed by the int 
instruction or by another 
interruption. The instruc¬ 
tion iret, if the stack is 
properly prepared, allows 
to a supervisor process to 
create a user process into 
particular code and data 
segments. 

j ump addressO , address 1 

This is an alternative way 
to change the data seg¬ 
ment, assigning the first 
argument to register DSO 
and the second to DS1. 
This instruction is avail¬ 
able only to a supervisor 
process. 




1140 


Version "F": 32-bit registers, big-endian, privileges 


Macrocode syntax 

Description 

jump addressO, address 1, start 

# label 

This is an alternative way 
to change the code seg¬ 
ment, assigning the first 
argument to register CSO , 
the second to CS1 and the 
third to PC. This instruc¬ 
tion is available only to a 
supervisor process. 

store_ssp 

Assign to register SSP the 
value of A. The register 
SSP is used to save the su¬ 
pervisor stack pointer. 

memcpy src, dst, count 

Copy count bytes from 
src to dst. Source and des¬ 
tination can be specified 
numerically or by labels. 

in %A %B, n 

Read, from the I/O ad¬ 
dress specified, a byte that 
is copied inside register A 
or B. Also the flags are up¬ 
dated. 

out %A %B, fi 

Write, to the I/O address 
specified, a byte that is 
read from register A or B. 

halt 

Stop the system. 




Version "F": 32-bit registers, big-endian, privileges 


1141 


Listing 14.59. Registers, flags and opcodes encoded for TKGate. 


registers A=0, 

CNI 

II 

o 

\—1 

II 

PQ 

II 

t> 

II 

H 

OO 

II 

P 

=5, 

SP=6 

, FP=7; 


registers carry 

=0, borrow=0. 

zero=l, 

negative=2, overtlow=3; 

//— 










op nop { 









map 

nop: 


0x00; 

// not operate 



operands { 

}; 

op store { 

— 

= { +0=0x00; 

}; }; 













map 

nop: 


0x00; 

// 

00000000 

= 

store 

%A, %A 

= nop 

map 

st_a_b 


0x01; 

// 

00000001 

= 

store 

%A, %B 


map 

st_a_c 


0x02; 

// 

00000010 

= 

store 

%A, %C 


map 

st_a_d 


0x03; 

// 

00000011 

= 

store 

%A, %D 


map 

st_a_i 


0x04; 

// 

00000100 

= 

store 

%A, %J 


map 

st_a_ j 


0x05; 

// 

00000101 

= 

store 

%A, %J 


map 

st_a_sp: 

0x06; 

// 

00000110 

= 

store 

%A, %SP 


map 

st_a_fp: 

0x07; 

// 

00000111 

= 

store 

%A, %FP 


map 

st_b_a 


0x08; 

// 

00001000 

= 

store 

%B, %A 


map 

nop: 


0x0 9; 

// 

00001001 

= 

store 

%B, %B 

= nop 

map 

st_b_c 


OxOA; 

// 

00001010 

= 

store 

%B, %C 


map 

st_b_d 


OxOB; 

// 

00001011 

= 

store 

%B, %D 


map 

st_b_i 


OxOC; 

// 

00001100 

= 

store 

%B, %I 


map 

st_b_ j 


OxOD; 

// 

00001101 

= 

store 

%B, %J 


map 

st_b_sp: 

OxOE; 

// 

00001110 

= 

store 

%B, %SP 


map 

st_b_fp: 

OxOF; 

// 

00001111 

= 

store 

%B, %FP 


operands { 









%1 

}; 

%2 

= { 

+0=0x00; 

+ 0 [3:3]=%1; 

+0[2:0]= 

=%2; }; 


}; 

op load { 









map 

nop: 


0x10; 

// 

00010000 

= 

load 

%A, %A = 

■ nop 

map 

ld_a_b 


0x11; 

// 

00010001 

= 

load 

%A, %B 


map 

ld_a_c 


0x12; 

// 

00010010 

= 

load 

%A, %C 


map 

1 d_a_d 


0x13; 

// 

00010011 

= 

load 

%A, %D 


map 

ld_a_i 


0x14; 

// 

00010100 

= 

load 

%A, %I 


map 

ld_a_ j 


0x15; 

// 

00010101 

= 

load 

%A, %J 


map 

ld_a_sp: 

0x16; 

// 

00010110 

= 

load 

%A, %SP 


map 

ld_a_fp: 

0x17; 

// 

00010111 

= 

load 

%A, %FP 


map 

1 d_b_a: 


0x18; 

// 

00011000 

= 

load 

%B, %A 









1142 


Version "F": 32-bit registers, big-endian, privileges 



map 

nop: 

0x19; 

// 

00011001 

= 

load %B,%B = 

nop 




map 

ld_b_c: 

OxlA; 

// 

00011010 

= 

load %B, %C 





map 

ld_b_d: 

OxlB; 

// 

00011011 

= 

load %B, %D 





map 

ld_b_i: 

OxlC; 

// 

00011100 

= 

load %B, %I 





map 

ld_b_j: 

OxlD; 

// 

00011101 

= 

load %B, %J 





map 

ld_b_sp: 

OxlE; 

// 

00011110 

= 

load %B, %SP 





map 

ld_b_fp: 

OxlF; 

// 

00011111 

= 

load %B,%FP 





operands { 










%i 

}; 

/ %2 = { 

+0=0x10; 

+ 0 [3:3]=%1; 

+0[2:0]=%2; }; 




}; 

// 










op load8 { 










map 

ld8ur_i: 

0x2 0; 

// 

00100000 

= 

load8 0, %I 

= A <- 

(i+j) 

unsign 


map 

ld8ur_j: 

0x21; 

// 

00100001 

= 

load8 0, %J 

= A <- 

(j) 

unsign 


map 

ld8ur_sp: 

0x22; 

// 

00100010 

= 

load8 0, %SP 

= A <- 

(SP+J) 

unsign 


map 

ld8ur_fp: 

0x23; 

// 

00100011 

= 

load8 0, %FP 

= A <— 

(FP+J) 

unsign 


map 

ld8sr_i: 

0x2 4; 

// 

00100100 

= 

load8 1, %I 

= A <- 

(I+J) 

signed 


map 

ld8sr_j: 

0x25; 

// 

00100101 

= 

load8 1, %J 

= A <— 

(J) 

signed 


map 

ld8sr_sp: 

0x2 6; 

// 

00100110 

= 

load8 1, %SP 

= A <- 

(SP+J) 

signed 


map 

ld8sr_fp: 

0x2 7; 

// 

00100111 

= 

load8 1, %FP 

= A <- 

(FP+J) 

signed 


map 

ld8u: 

0x4 0; 

// 

01000000 

= 

load8 0, n 

= A <- 

n 

unsign 


map 

ld8s : 

0x41; 

// 

01000001 

= 

load8 1, n 

= A <- 

n 

signed 


operands { 










#1 

(%2) = { 

+ 0=0x2 0; 

+ 0 [2:2]=#1; 

+0[1:0]=%2; }; 





#1 

}; 

.,#2 = { 

+0=0x40; 

+0[0:0]=#1; 

+ 1 

=#2 [7 : 0]; }; 




}; 

op loadl6 { 










map 

ldl6ur_i: 

0x28; 

// 

00101000 

= 

loadl6 0, %I 

= A <— 

(I+J) 

unsign 


map 

ldl6ur_j: 

0x29; 

// 

00101001 

= 

loadl6 0, %J 

= A <— 

(J) 

unsign 


map 

ldl6ur_sp 

: 0x2A; 

// 

00101010 

= 

loadl6 0, %SP 

= A <— 

(SP+J) 

unsign 


map 

ldl6ur_fp 

: 0x2B; 

// 

00101011 

= 

loadl6 0, %FP 

= A <- 

(FP+J) 

unsign 


map 

ldl6sr_i: 

0x2C; 

// 

00101100 

= 

loadl6 1, %I 

= A <- 

(I+J) 

signed 


map 

ldl6sr_j: 

0x2D; 

// 

00101101 

= 

loadl6 1, %J 

= A <- 

(I+J) 

signed 


map 

ldl6sr_sp 

: 0x2E; 

// 

00101110 

= 

loadl6 1, %SP 

= A <— 

(SP+J) 

signed 


map 

ldl6sr_fp 

: 0x2F; 

// 

00101111 

= 

loadl6 1, %FP 

= A <— 

(FP+J) 

signed 


map 

ldl6u: 

0x42; 

// 

01000010 

= 

loadl6 0, n 

= A <— 

n 

unsign 


map 

ldl6s: 

0x4 3; 

// 

01000011 

= 

load!6 1, n 

= A <- 

n 

signed 


operands { 














Version "F": 32-bit registers, big-endian, privileges 


1143 



#1 

, (%2) = { 

+ 0 = 0x2 8; 

+ 0 [2:2]=#1; 

+ 0 [1:0]=% 

2; 

}; 





#1 

}; 

/ #2 = { 

+0=0x42; 

+0[0:0]=#1; 

+1 

=#2 [15: 

8] ; 

+2=#2 [7 

:0] ; }; 


}; 

op load24 { 












map 

ld24ur_i: 

0x30; 

// 

00110000 

= 

load24 

o, 

%I = 

A 

<- (%+J) 

unsign 


map 

ld24ur_j: 

0x31; 

// 

00110001 

= 

load24 

o, 

%J = 

A 

<~ (J) 

unsign 


map 

ld24ur_sp 

: 0x32; 

// 

00110010 

= 

load24 

0, 

%SP = 

A 

<- (SP+J) 

unsign 


map 

ld24ur_fp 

: 0x33; 

// 

00110011 

= 

load24 

0, 

%FP = 

A 

<- (FP+J) 

unsign 


map 

ld24sr_i: 

0x34; 

// 

00110100 

= 

load24 

lr 

%I = 

A 

<- (I+J) 

signed 


map 

ld24sr_j: 

0x35; 

// 

00110101 

= 

load24 

lr 

%J = 

A 

<~ (J) 

signed 


map 

ld24sr_sp 

: 0x36; 

// 

00110110 

= 

load24 

lr 

%SP = 

A 

<- (SP+J) 

signed 


map 

ld24sr_fp 

: 0x37; 

// 

00110111 

= 

load24 

lr 

%FP = 

A 

<- (FP+J) 

signed 


map 

ld24u: 

0x4 4; 

// 

01000100 

= 

load24 

Or 

n = 

A 

<- n 

unsign 


map 

ld24s: 

0x4 5; 

// 

01000101 

= 

load24 

lr 

n = 

A 

<- n 

signed 


operands { 












#i 

, (%2) = { 

+0=0x30; 

+0[2:2]=#1; 

+0[1:0]=% 

2; 

}; 





#i 

r #2 = { 

+0=0x44; 

+ 0 [ 0:0]=#1; 

+ 1 

=#2[24: 

16] 

; +2=#2 [15:8]; 



}; 


+ 3=#2 [7 : 

0] ; 

}; 








}; 

op load32 { 












map 

ld32ur_i : 

0x38 ; 

// 

00111000 

= 

load32 

Or 

%I = 

A 

<- (I+J) 

unsign 


map 

ld32ur_j : 

0x3 9; 

// 

00111001 

= 

load32 

Or 

%J = 

A 

<~ (J) 

unsign 


map 

ld32ur_sp 

: 0x3A; 

// 

00111010 

= 

load32 

Or 

%SP = 

A 

<- (SP+J) 

unsign 


map 

ld32ur_fp 

: 0x3B; 

// 

00111011 

= 

load32 

Or 

%FP = 

A 

<- (FP+J) 

unsign 


map 

ld32sr_i : 

0 x 3 C; 

// 

00111100 

= 

load32 

lr 

%I = 

A 

<- (I+J) 

signed 


map 

ld32sr_j : 

0x3D; 

// 

00111101 

= 

load32 

lr 

%J = 

A 

<~ (J) 

signed 


map 

ld32sr_sp 

: 0x3E; 

// 

00111110 

= 

load32 

lr 

%SP = 

A 

<- (SP+J) 

signed 


map 

ld32sr_fp 

: 0x3F; 

// 

00111111 

= 

load32 

lr 

%FP = 

A 

<- (FP+J) 

signed 


map 

ld32u : 

0x4 6; 

// 

01000110 

= 

load32 

Or 

n = 

A 

<- n 

unsign 


map 

ld32s : 

0x4 7; 

// 

01000111 

= 

load32 

lr 

n = 

A 

<- n 

signed 


operands { 












#i 

, (% 2) = { 

+0=0x38 ; 

+0[2:2] =#1 ; 

+0[1:0]=% 

2; 

}; 





#i 

/ #2 = { 

+0=0x46 ; 

+ 0 [ 0:0] =#1 ; 









}; 


+ 1=#2 [31 

: 24 ] 

; +2=#2[23: 

16]; +3 

;=#2 [15:8] 

1; 

+4=#2[7:0] 

]; }; 

}; 

op lea 

{ 












map 

lea_a_i : 

0x4 8; 

// 

01001000 

= 

lea %A, 

(%I) = 

A 

<- lea (I+J) 





1144 


Version "F": 32-bit registers, big-endian, privileges 


map 

lea_a_j: 

0x4 9; 

// 

01001001 

map 

lea_a_sp 

0x4A; 

// 

01001010 

map 

lea_a_fp 

0 x 4 B; 

// 

01001011 

map 

lea_b_i: 

0 x 4 C; 

// 

01001100 

map 

lea_b_j: 

0x4D; 

// 

01001101 

map 

lea_b_sp 

0x4E; 

// 

01001110 

map 

lea_b_fp 

0x4F; 

// 

01001111 

operands { 




%i 

}; 

, (%2) = -1 

+0=0x48; 

+0[2:2]=%1; 

swap { 




map 

swap_a_a 

0x50; 

// 

01010000 

map 

swap_a_b 

0x51; 

// 

01010001 

map 

swap_a_c 

0x52; 

// 

01010010 

map 

swap_a_d 

0x53; 

// 

01010011 

map 

swap_a_i 

0x54; 

// 

01010100 

map 

swap_a_j 

0x55; 

// 

01010101 

map 

swap_a_sp: 0x56; 

// 

01010110 

map 

swap_a_fp: 0x57; 

// 

01010111 

map 

swap_b_a 

0x58; 

// 

01011000 

map 

swap_b_b 

0x5 9; 

// 

01011001 

map 

swap_b_c 

0x5A; 

// 

01011010 

map 

swap_b_d 

0x5B; 

// 

01011011 

map 

swap_b_i 

0x5C; 

// 

01011100 

map 

swap_b_j 

0x5D; 

// 

01011101 

map 

swap_b_sp: 0x5E; 

// 

01011110 

map 

swap_b_fp: 0x5F; 

// 

01011111 

operands { 




5-1 

o -L 

}; 

r %2 = -j 

+0=0x50; 

+0[3:3]=%1; 

> store8 { 




map 

st8r_i: 

0x60; 

// 

01100000 

map 

st8r_j: 

0x61; 

// 

01100001 

map 

st8r_sp: 

0x62; 

// 

01100010 

map 

st8r_fp: 

0x63; 

// 

01100011 

operands { 




(% 

;1) = { +0=0x60; +0 

[1:0 

]=%i; }; 


}; 


= lea 

o\o 

(%J) 

= 

A 

<- lea 

(J) 

= lea 

fS 

o\o 

(%SP) 

= 

A 

<- lea 

(SP+J) 

= lea 

fS 

o\o 

( %FP) 

= 

A 

<- lea 

(FP+J) 

= lea 

o\o 

(%I) 

= 

B 

<- lea 

(I+J) 

= lea 

o\o 

(%J) 

= 

B 

<- lea 

(J) 

= lea 

o\o 

(%SP) 

= 

B 

<- lea 

(SP+J) 

= lea 

o\o 

( %FP) 


B 

<- lea 

(FP+J) 

+ 0 [1: 0 

] =%2 

; }; 






— 

swap 

< 

* 

o\o 

%A 

not 

implemented 

= 

swap 

%A, 

%B 

not 

implemented 

= 

swap 

%A, 

%C 

not 

implemented 

= 

swap 

%A, 

%D 

not 

implemented 

= 

swap 

%A, 

%I 

not 

implemented 

= 

swap 

%A, 

%J 

not 

implemented 

= 

swap 

%A, 

%SP 

not 

implemented 

= 

swap 

%A, 

%FP 

not 

implemented 

= 

swap 

%B, 

%A 

not 

implemented 

= 

swap 

%B, 

%B 

not 

implemented 

= 

swap 

%B, 

%C 

not 

implemented 

= 

swap 

%B, 

%D 

not 

implemented 

= 

swap 

%B, 

%I 

not 

implemented 

= 

swap 

%B, 

%J 

not 

implemented 

= 

swap 

%B, 

%SP 

not 

implemented 

= 

swap 

%B, 

%FP 

not 

implemented 

+0[2:0] 

=%2; 

}; 




= store8 

(%I) 

= M(I+J) <- A 

= store8 

(%J) 

= M(J) <- A 

= store8 

(%SP) 

= M(SP+J) <- A 

= store8 

(%FP) 

= M (FP+J) <- A 







Version "F": 32-bit registers, big-endian, privileges 


1145 


}; 

op storel6 { 










map stl6r_i: 

0x64; 

// 

01100100 

= 

storel6 

(%I) 

= 

M(I+J) <- A 

map stl6r_j: 

0x65; 

// 

01100101 

= 

storel6 

(%J) 

= 

M(J) <- A 

map stl6r_sp: 

0x66; 

// 

01100110 

= 

storel6 

(%SP) 

= 

M(SP+J) <- A 

map stl6r_fp: 

0x67; 

// 

01100111 

= 

storel6 

( %FP) 

= 

M(FP+J) <- A 

operands { 










(%1) = { 

}; 

+ 0= 

0x64; +0 [1:0 

]=%i; }; 






}; 

op store24 { 










map st24r_i: 

0x68; 

// 

01101000 

= 

store24 

(%I) 

= 

M(I+J) <- A 

map st24r_j: 

0x69; 

// 

01101001 

= 

store24 

(%J) 

= 

M(J) <- A 

map st24r_sp: 

0x6A; 

// 

01101010 

= 

store24 

(%SP) 

= 

M(SP+J) <- A 

map st24r_fp: 

0x6B; 

// 

01101011 

= 

store24 

( %FP) 

= 

M (FP+J) <- A 

operands { 










(%n = { 

}; 

+ 0= 

0x68; +0[1:0 

]=%i; }; 






}; 

op store32 { 










map st32r_i: 

0x6C; 

// 

01101100 

= 

store32 

(%I) 

= 

M(I+J) <- A 

map st32r_j: 

0x6D; 

// 

01101101 

= 

store32 

(%J) 

= 

M(J) <- A 

map st32r_sp: 

0x6E; 

// 

01101110 

= 

store32 

(%SP) 

= 

M(SP+J) <- A 

map st32r_fp: 

0x6F; 

// 

01101111 

= 

store32 

(%FP) 

= 

M (FP+J) <- A 

operands { 










(%1) = { 

}; 

+ 0= 

: 0x6C; +0 [ 1: 0 

]=%i; }; 






}; 

op push { 










map push_a 


0x7 0; 

// 

01110000 

= 

push %A 




map push_b 


0x71; 

// 

01110001 

= 

push %B 




map push_c 


0x72; 

// 

01110010 

= 

push %C 




map push_d 


0x7 3; 

// 

01110011 

= 

push %D 




map push_i 


0x7 4; 

// 

01110100 

= 

push %I 




map push_j 


0x7 5; 

// 

01110101 

= 

push %J 




map push_sp: 

0x7 6; 

// 

01110110 

= 

push %SP 




map push_fp: 

0x7 7; 

// 

01110111 

= 

push %FP 




operands { 










%1 = { +0=0x70; +0 [2 

: 0] = 

%i; }; 






}; 














1146 


Version "F": 32-bit registers, big-endian, privileges 


}; 

op pop { 


map 

pop_a 


0x7 8; 

// 

01111000 

= 

pop 

%A 

map 

pop_b 


0x7 9; 

// 

01111001 

= 

pop 

%B 

map 

pop_c 


0x7A; 

// 

01111010 

= 

pop 

%C 

map 

pop_d 


0x7B; 

// 

01111011 

= 

pop 

%D 

map 

pop_i 


0x7 C; 

// 

01111100 

= 

pop 

%I 

map 

pop_j 


0x7D; 

// 

01111101 

= 

pop 

%J 

map 

pop_sp: 

0x7E; 

// 

01111110 

= 

pop 

%SP 

map 

pop_fp: 

0x7F; 

// 

01111111 

= 

pop 

%FP 

operands { 







o ■ 
o . 

1 = { +0= 

: 0x78; +0 [2 

: 0 ] = 

: %i; }; 





0x80; // 

+ 0=0x8 0; 


0x81; // 

+0=0x81; 


10000000 

}; }; 


10000001 

}; }; 


= equal8 %A = 


= equal 16 %A = 


10000010 

}; }; 


= equal24 %A = 


}; 

}; 

op equal8 { 
map equal8s: 
operands { - = { 

}; 

op equall6 { 
map equall6s: 
operands { - = { 

}; 

op equal24 { 

map equal24s: 0x82; // 

operands { - = { +0=0x82; 

}; 

op equal32 { 

map equal32s: 0x83; // 10000011 = equal32 %A = 

operands { - = { +0=0x83; }; }; 

}; 

op not8 { 
map not8s: 
operands { - = { 

}; 

op notl6 { 
map notl6s: 
operands { - = { 

}; 

op not24 { 

map not24s: 0x86; // 10000110 = not24 %A = A 


0x84; // 

+0=0x84; 


0x85; // 

+0=0x85; 


10000100 

}; }; 


10000101 

}; }; 


= not 8 %A = A 


= not 16 %A = A 


A <- A 


A <- A 


A <- A 


A <- A 


<- ~A 


<- ~A 


<— ~A 





Version "F": 32-bit registers, big-endian, privileges 


1147 


operands { - 

}; 

op not32 { 
map not32s: 
operands { - 

}; 

op and8 { 
map and8s: 
operands { - 

}; 

op andl6 { 
map andl6s: 
operands { - 

}; 

op and24 { 
map and24s: 
operands { - 

}; 

op and32 { 
map and32s: 
operands { - 

}; 

op nand8 { 
map nand8s: 
operands { - 

}; 

op nandl6 { 
map nandl6s: 
operands { - 

}; 

op nand24 { 
map nand24s: 
operands { - 

}; 

op nand32 { 
map nand32s: 
operands { - 

}; 

op or8 { 
map or8s: 


{ +0=0x86; }; }; 


0x87; // 10000111 = not32 %A = 

{ +0=0x87; }; }; 


0x88; // 10001000 = and8 %A = 

{ +0=0x88; }; }; 


0x89; // 10001001 = andl6 %A = 

{ +0=0x89; }; }; 


0x8A; // 10001010 = and24 %A = 

{ +0=0x8A; }; }; 


0x8B; // 10001011 = and32 %A = 

{ +0=0x8B; }; }; 


0x8C; // 10001100 = nand8 %A = 

{ +0=0x8C; }; }; 


0x8D; // 10001101 = nandl6 %A = 

{ +0=0x8D; }; }; 


0x8E; // 10001110 = nand24 %A = 

{ +0=0x8E; }; }; 


0x8F; // 10001111 = nand32 %A = 

{ +0=0x8F; }; }; 


0x90; // 10010000 = or8 %A = A 


<— ~A 


<- A&B 


<- A&B 


<- A&B 


<- A&B 


A <- ~A&B 


A <- ~A&B 


A <- ~A&B 


A <- ~A&B 


<- AjB 



1148 


Version "F": 32-bit registers, big-endian, privileges 


operands { - 

}; 

op orl6 { 
map or16s: 
operands { - 

}; 

op or24 { 
map or24s: 
operands { - 

}; 

op or32 { 
map or32s: 
operands { - 

}; 

op nor8 { 
map nor8s: 
operands { - 

}; 

op norl6 { 
map nor16s: 
operands { - 

}; 

op nor24 { 
map nor24s: 
operands { - 

}; 

op nor32 { 
map nor32s: 
operands { - 

}; 

op xor8 { 
map xor8s: 
operands { - 

}; 

op xorl6 { 
map xorl6s: 
operands { - 

}; 

op xor24 { 
map xor24s: 


{ +0=0x90; }; }; 


0x91; // 10010001 

{ +0=0x91; }; }; 


0x92; // 10010010 

{ +0=0x92; }; }; 


0x93; // 10010011 

{ +0=0x93; }; }; 


0x94; // 10010100 

{ +0=0x94; }; }; 


0x95; // 10010101 

{ +0=0x95; }; }; 


0x96; // 10010110 

{ +0=0x96; }; }; 


0x97; // 10010111 

{ +0=0x97; }; }; 


0x98; // 10011000 

{ +0=0x98; }; }; 


0x99; // 10011001 

{ +0=0x99; }; }; 


0x9A; // 10011010 


= or 16 %A = A <- A/B 


= or24 %A = A <— A/B 


= or32 %A = A <- A/B 


= nor8 %A = A <- ~AIB 


= nor16 %A = A <- ~AjB 


= nor24 %A = A <— ~A/B 


= nor32 %A = A <- ~AIB 


= xor8 %A = A <— A*B 


= xorl6 %A = A <- A*B 


= xor24 %A = A <- A*B 



Version "F": 32-bit registers, big-endian, privileges 


1149 


operands { - 

}; 

op xor32 { 
map xor32s: 
operands { - 

}; 

op nxor8 { 
map nxor8s: 
operands { - 

}; 

op nxorl6 { 
map nxorl6s: 
operands { - 

}; 

op nxor24 { 
map nxor24s: 
operands { - 

}; 

op nxor32 { 
map nxor32s: 
operands { - 

}; 

op add8 { 
map add8s: 
operands { - 

}; 

op addl6 { 
map addl6s: 
operands { - 

}; ' 

op add24 { 
map add24s: 
operands { - 

}; 

op add32 { 
map add32s: 
operands { - 

}; 

op sub8 { 
map sub8s: 


{ +0=0x9A; }; }; 


0x9B; // 10011011 = xor32 %A = A <- 

{ +0=0x9B; }; }; 


0x9C; // 10011000 = nxor8 %A = A <- ~A*B 

{ +0=0x9C; }; }; 


0x9D; // 10011001 = nxorl6 %A = A < - A A B 

{ +0=0x9D; }; }; 


0x9E; // 10011010 = nxor24 %A = A <- ~A*B 

{ +0=0x9E; }; }; 


0x9F; // 10011011 = nxor32 %A = A <- ~A*B 

{ +0=0x9F; }; }; 


OxAO; // 10100000 = add8 %A = A <- A+B 

{ +0=0xA0; }; }; 


OxAl; // 10100001 = addl6 %A = A <- A+B 

{ +0=0xAl; }; }; 


0xA2; // 10100010 = add24 %A = A <- A+B 

{ +0=0xA2; }; }; 


0xA3; // 10100011 = add32 %A = A <- A+B 

{ +0=0xA3; }; }; 


0xA4; // 10100000 = sub8 %A = A <- A-B 



1150 


Version "F": 32-bit registers, big-endian, privileges 


operands { - 

}; 

op subl6 { 
map subl6s: 
operands { - 

}; 

op sub24 { 
map sub24s: 
operands { - 

}; 

op sub32 { 
map sub32s: 
operands { - 

}; 

op addc8 { 
map addc8s: 
operands { - 

}; 

op addcl6 { 
map addcl6s: 
operands { - 

}; 

op addc24 { 
map addc24s: 
operands { - 

}; 

op addc32 { 
map addc32s: 
operands { - 

}; 

op subb8 { 
map subb8s: 
operands { - 

}; 

op subbl6 { 
map subbl6s: 
operands { - 

}; 

op subb24 { 
map subb24s: 


{ +0=0xA4; }; }; 


0xA5; // 10100001 = subl6 %A = A <- 

{ +0=0xA5; }; }; 


0xA6; // 10100010 = sub24 %A = A <- 

{ +0=0xA6; }; }; 


0xA7; // 10100011 = sub32 %A = A <— 

{ +0=0xA7; }; }; 


0xA8; // 10101000 = addc8 %A = A <- 

{ +0=0xA8; }; }; 


0xA9; // 10101001 = addcl6 %A = A <— 

{ +0=0xA9; }; }; 


OxAA; // 10101010 = addc24 %A = A <- 

{ +0=0xAA; }; }; 


OxAB; // 10101011 = addc32 %A = A <- 

{ +0=0xAB; }; }; 


OxAC; // 10101100 = subb8 %A = A <— 

{ +0=0xAC; }; }; 


Ox AD; // 10101101 = subbl6 %A = A <- 

{ +0=0xAD; }; }; 


OxAE; // 10101110 = subb24 %A = A <— 


A-B 


A-B 


A-B 


A+B+c 


A+B+c 


A+B+c 


A+B+c 


A-B-b 


A-B-b 


A-B-b 



Version "F": 32-bit registers, big-endian, privileges 


1151 


operands { - 

}; 

op subb32 { 
map subb32s: 
operands { - 

}; 

op lshl8 { 
map lshl8s: 
operands { - 

}; 

op lshll6 { 
map lshll6s: 
operands { - 

}; 

op lshl24 { 
map lshl24s: 
operands { - 

}; ~ 

op lshl32 { 
map lshl32s: 
operands { - 

}; 

op lshr8 { 
map lshr8s: 
operands { - 

}; 

op lshrl6 { 
map lshr16s: 
operands { - 

}; ~ 

op lshr24 { 
map lshr24s: 
operands { - 

}; 

op lshr32 { 
map lshr32s: 
operands { - 

}; 

op ashl8 { 
map ashl8s: 


{ +0=0xAE; }; }; 


OxAF; // 10101111 = subb32 %A = A <- A-B-b 

{ +0=0xAF; }; }; 


OxBO; // 10110000 = lshl8 %A = A <— lshl A 

{ +0=0xB0; }; }; 


OxBl; // 10101101 = lshll6 %A = A <- lshl A 

{ +0=0xBl; }; }; 


0xB2; // 10101110 = lshl24 %A = A <- lshl A 

{ +0=0xB2; }; }; 


0xB3; // 10101111 = lshl32 %A = A <— lshl A 

{ +0=0xB3; }; }; 


0xB4; // 10110000 = lshr8 %A = A <- lshr A 

{ +0=0xB4; }; }; 


0xB5; // 10110001 = lshrl6 %A = A <- lshr A 

{ +0=0xB5; }; }; 


0xB 6; // 10110010 = lshr24 %A = A <— lshr A 

{ +0=0xB6; }; }; 


0xB7; // 10110011 = lshr32 %A = A <- lshr A 

{ +0=0xB7; }; }; 


0xB8; // 10111000 = ash!8 %A = A <- ashl A 



1152 


Version "F": 32-bit registers, big-endian, privileges 


operands { - = 

}; 

op ashll6 { 
map ashll6s: 
operands { - = 

}; 

op ashl24 { 
map ashl24s: 
operands { - = 

}; 

op ashl32 { 
map ashl32s: 
operands { - = 

}; 

op ashr8 { 
map ashr8s: 
operands { - = 

}; 

op ashrl6 { 
map ashr16s : 
operands { - = 

}; 

op ashr24 { 
map ashr24s: 
operands { - = 

}; 

op ashr32 { 
map ashr32s: 
operands { - = 

}; 

op rotcl8 { 
map rotcl8s: 
operands { - = 

}; 

op rotcll6 { 
map rotcll6s: 
operands { - = 

}; 

op rotcl24 { 
map rotcl24s: 


{ +0=0xB8; }; }; 


0xB9; // 10111001 = ashll6 %A = A <— ashl A 

{ +0=0xB9; }; }; 

OxBA; // 10111010 = ashl24 %A = A <- ashl A 

{ +0=0xBA; }; }; 

OxBB; // 10111011 = ashl32 %A = A <— ashl A 

{ +0=0xBB; }; }; 


OxBC; // 10111100 = ashr8 %A = A <- ashr A 

{ +0=0xBC; }; }; 

OxBD; // 10111101 = ashr16 %A = A <- ashr A 

{ +0=0xBD; }; }; 

OxBE; // 10111110 = ashr24 %A = A <- ashr A 

{ +0=0xBE; }; }; 


OxBF; // 10111111 = ashr32 %A = A <- ashr A 

{ +0=0xBF; }; }; 


OxCO; // 11000000 = rotcl8 %A = A <— rotcl A 

{ +0=0xC0; }; }; 

OxCl; // 11000001 = rotcll6 %A = A <- rotcl A 

{ +0=0xCl; }; }; 


0xC2; // 11000010 = rotcl24 %A = A <- rotcl A 



Version "F": 32-bit registers, big-endian, privileges 


1153 


operands { - = 

}; 

op rotcl32 { 
map rotcl32s: 
operands { - = 

}; 

op rotcr8 { 
map rotcr8s: 
operands { - = 

}; 

op rotcrl6 { 
map rotcrl6s: 
operands { - = 

}; 

op rotcr24 { 
map rotcr24s: 
operands { - = 

}; 

op rotcr32 { 
map rotcr32s: 
operands { - = 

}; 

op rotl8 { 
map rotl8s: 
operands { - = 

}; 

op rotll6 { 
map rot116s : 
operands { - = 

}; ~ 

op rotl24 { 
map rotl24s: 
operands { - = 

}; 

op rotl32 { 
map rotl32s: 
operands { - = 

}; 

op rotr8 { 
map rotr8s: 


{ +0=0xC2; }; }; 


0xC3; // 11000011 = rotcl32 %A = A <- rotcl A 

{ +0=0xC3; }; }; 


0xC4; // 11000100 = rotcr8 %A = A <- rotcr A 

{ +0=0xC4; }; }; 


0xC5; // 11000101 = rotcrl6 %A = A <- rotcr A 

{ +0=0xC5; }; }; 


0xC6; // 11000110 = rotcr24 %A = A <- rotcr A 

{ +0=0xC6; }; }; 


0xC7; // 11000111 = rotcr32 %A = A <- rotcr A 

{ +0=0xC7; }; }; 


0xC8; // 11001000 = rotl8 %A = A <- rotl A 

{ +0=0xC8; }; }; 


0xC9; // 11001001 = rotll6 %A = A <- rotl A 

{ +0=0xC9; }; }; 


OxCA; // 11001010 = rotl24 %A = A <— rotl A 

{ +0=0xCA; }; }; 


OxCB; // 11001011 = rot132 %A = A <- rotl A 

{ +0=0xCB; }; }; 


OxCC; // 11001100 = rotr8 %A = A <- rotr A 



1154 


Version "F": 32-bit registers, big-endian, privileges 


operands { - = 

}; 

op rotrl6 { 
map rotrl6s: 
operands { - = 

}; 

op rotr24 { 
map rotr24s: 
operands { - = 

}; 

op rotr32 { 
map rotr32s: 
operands { - = 

}; 

op utrunc8 { 
map utrunc8: 
operands { - = 

}; 

op utruncl6 { 
map utruncl6: 
operands { - = 

}; 

op utrunc24 { 
map utrunc24: 
operands { - = 

}; 

op utrunc32 { 
map utrunc32: 
operands { - = 

}; 

op strunc8 { 
map strunc8: 
operands { - = 

}; 

op struncl6 { 
map struncl6: 
operands { - = 

}; 

op strunc24 { 
map strunc24: 


{ +0=0xCC; }; }; 


OxCD; // 11001101 = rotrl6 %A = A <— 

{ +0=0xCD; }; }; 


OxCE; // 11001110 = rotr24 %A = A <— 

{ +0=0xCE; }; }; 


OxCF; // 11001111 = rotr32 %A = A <- 

{ +0=0xCF; }; }; 


OxDO; // 11010000 = utrunc8 %A = A 

{ +0=0xD0; }; }; 


OxDl; // 11010001 = utruncl6 %A = A 

{ +0=0xDl; }; }; 


0xD2; // 11010010 = utrunc24 %A = A 

{ +0=0xD2; }; }; 


0xD3; // 11010011 = utrunc32 %A = A 

{ +0=0xD3; }; }; 


0 xD 4; // 11010100 = strunc8 %A = A 

{ +0=0xD4; }; }; 


0xD5; // 11010101 = struncl6 %A = A 

{ +0=0xD5; }; }; 


0xD6; // 11010110 = strunc24 %A = A 


rotr A 


rotr A 


rotr A 


<- utrunc A 


<- utrunc A 


<- utrunc A 


<- utrunc A 


<- strunc A 


<- strunc A 


<- strunc A 



Version "F": 32-bit registers, big-endian, privileges 


1155 


operands { - = { +0=0xD6; }; }; 

}; 

op strunc32 { 

map strunc32: 0xD7; // 11010111 

operands { - = { +0 = 0xD7; }; }; 

}; 

op clear { 

map clear_a: 0xD8; // 11011000 

map clear_b: 0xD9; // 11011001 

operands { 

%1 = { +0=0xD8; +0[0:0]=%1; }; 

}; 

}; 

op set { 

map set_a: OxDA; // 11011010 

map set_b: OxDB; // 11011011 

operands { 

%1 = { +0=0xDA; +0[0:0]=%1; }; 

}; 

}; 

op comp { 

map comp: OxDC; // 11011100 

operands { - = { +0=0xDC; }; }; 

}; 

op test { 

map test: OxDD; // 11011101 

operands { - = { +0=0xDD; }; }; 

}; 

op flag_c { 

map flag_c_0: OxDE; // 11011110 

map flag_c_l: OxDF; // 11011111 

operands { 

#1 = { +0=0xDE; +0[0:0]=#1; }; 

}; 

}; 

op flag_i { 

map flag_i_0: OxEO; // 11100000 

map flag_i_l: OxEl; // 11100001 

operands { 

#1 = { +0=0xE0; +0[0:0]=#1; }; 


= strunc32 %A = A <— strunc A 


= clear %A = A <- 0 
= clear %B = B <- 0 


= set %A = A <- -1 
= set %B = B < 1 


= update FL with A-B 


= update FL with A&B 


= flag_c 0 = clear carry flag 
= flag_c 1 = set carry flag 


= flag_i 0 = clear irq enable flag 
= flag_i 1 = set irq enable flag 



1156 


Version "F": 32-bit registers, big-endian, privileges 



}; 








}; 









op flag_t { 








map 

flag_t_0 


0xE2; 

// 

11100010 = 

flag_t 0 = clear supervisor flag 


map 

f lag_t_l 


0xE3; 

// 

11100011 = 

flag_t 1 = set supervisor flag 


operands { 








#1 

}; 

= { +0=0xE2; +0[0: 

0] = 

#1; }; 



}; 

op call { 








map 

callr_i: 


0 xE 4; 

// 

11100100 = 

call 

%i 


map 

callr_j: 


0xE5; 

// 

11100101 = 

call 

%j 


map 

call: 


0xE6; 

// 

11100110 = 

call 

#ref 


operands { 








%i 

= { +0=0xE4; +0[0: 

0] = 

%i; }; 




#1 

= { +0=0xE6; +1=#1[31 

:2 4]; +2=#1[23:16]; +3=#1[15:8]; 


}; 

+4=#1[7:0]; }; 





}; 

op return { 








map 

return: 


0xE7; 

// 

11100111 = 

return 

}; 

Of 

operands { - 

= 

{ +0=0xE7; 

}; }; 



) j ump { 








map 

jump_c_0 


0 xE 8; 

// 

11101000 = 

jump 

%carry,0,#ref 


map 

jump_c_l 


0xE9; 

// 

11101001 = 

jump 

%carry,1,#ref 


map 

jump_z_0 


OxEA; 

// 

11101010 = 

jump 

%zero, 0, #ref 


map 

jump_z_l 


OxEB; 

// 

11101011 = 

jump 

%zero, 1, #ref 


map 

jump_n_0 


OxEC; 

// 

11101100 = 

jump 

^negative, 0, #ref 


map 

jump_n_l 


OxED; 

// 

11101101 = 

jump 

^negative, 1, #ref 


map 

jump_v_0 


OxEE; 

// 

11101110 = 

jump 

%overflow, 0, #ref 


map 

jump_v_l 


OxEF; 

// 

11101111 = 

jump 

%overflow, 1, #ref 


map 

jumpr_i: 


OxFO; 

// 

11110000 = 

jump 

%I 


map 

jumpr_j: 


OxFl; 

// 

11110001 = 

jump 

% J 


map 

jump: 


OxFC; 

// 

11111100 = 

jump 

#ref 


map 

jump_cs: 


OxFD; 

// 

11111101 = 

jump 

csO, csl, #ref 


map 

jump_ds: 


OxFE; 

// 

11111110 = 

jump 

dsO, dsl 


operands { 








%1 

= 

{ 

+0=0xF0; 

+0[0:0]=%1; } 

r 



%1 

,#2,#3 = 

{ 

+0=0xE8; 

+ 0 [2:1]=%1; +0 [0:0 

] =#2; 




Version "F": 32-bit registers, big-endian, privileges 


1157 


#1 


#1,#2,#3 = 


]; }; 

; +4=#1[7:0]; }; 


# 1 , #2 


+1=#3[31:24]; +2=#3[23:16]; +3=#3[15:8]; +4=#3[7:0 
{ +0=0xFC; 

+1=#1[31:24]; +2=#1[23:16]; +3=#1[15 
{ +0=0xFD; 

+ 1=#1 [31:24] 

+ 5=#2 [31:24] 

+ 9=#3 [31:24] 

+ 12=#3 [7 : 0]; }; 

{ +0=0xFE; 

+ 1=#1 [31:24]; +2=#1[23 :16]; +3=#1[15:8]; +4=#1[7:0]; 

+ 5=#2[31:24] ; +6=#2[23:16] ; +7=#2[15:8]; +8=#2[7:0]; }; 


+2=#1[23:16]; +3=#1[15:8]; +4=#1[7:0 
+6=#2[23:16]; +7=#2[15:8]; +8=#2[7:0 
+10=#3[23:16]; +11=#3[15:8]; 


]; 
]; 


}; 

}; 

op imrl { 
map imrl: 
operands { 

#1 = { +0=0xF2; +1=#1 [7:0]; }; 

}; 

}; 

op ivtl { 
map ivtl: 
operands { 

#1 = { +0 
+1 

}; 

}; 

op int { 
map int: 
operands { 

#1 = { +0=0xF 4; +1=#1 [7:0]; }; 

}; 


0xF2; // 11110010 = imrl n = IRQ mask register load 


0xF3; // 11110011 = ivtl #ref = load INT vector table 

0xF3; 

#1[31:2 4]; +2=#1[23:16]; +3=#1[15:8]; +4=#1[7:0]; }; 


0xF4; // 11110100 = int n = soft interrupt call 


}; 

op iret { 

map iret: 0xF5; // 11110101 = iret = interrupt return 

operands { - = { +0=0xF5; }; }; 

}; 

op in { 

map in_a: 0xF6; // 11110110 = in %A,n = A <- I/O device 

map in_b: 0xF7; // 11110111 = in %B,n = B <- I/O device 

operands { 



1158 


Version "F": 32-bit registers, big-endian, privileges 


%1,#2 = { +0=0xF6; +0[0:0]=%1; +1=#2[7:0]; }; 

}; 

}; 


op out { 

map out_a: 0xF8; // 11111000 = out %A,n = I/O device <- A 

map out_b: 0xF9; // 11111001 = out %B,n = I/O device <- B 

operands { 

%1,#2 = { +0=0xF8; +0[0:0]=%1; +1=#2[7:0]; }; 

}; 

}; 

op memcpy { 

map memcpy: OxFA; // 11111010 = memcpy #src,#dst, size 

operands { 

#1,#2,#3 = { +0=0xFA; 

+1=#1[31:24]; +2=#1[23:16]; +3=#1[15:8]; +4=#1[7:0]; 
+5=#2[31:24]; +6=#2[23:16]; +7=#2[15:8]; +8=#2[7:0]; 
+9=#3[31:24]; +10=#3[23:16]; +11=#3[15:8]; +12=#3[7:0]; 


}; 

}; 

}; 

op store_ssp { 

map st_a_ssp: OxFB; // 11111011 = SSP <— A 

operands { 

- = { +0 = 0xFB; }; 

}; 

}; 

op halt { 


map halt: OxFF; // 11111111 = halt 

operands { - = { +0=0xFF; }; }; 

}; 


14.21 Data initialization 

This version of the simple CPU accesses the memory in big-endian 
mode. As the TKGate compiler initializes variables in little-endian 
mode, it is necessary to define some instructions that do the same, 
but in the right byte order. These instructions are declared as if they 



1159 


Version "F": 32-bit registers, big-endian, privileges 

were opcodes, but actually there is no opcode at all. 


Listing 14.60. Variable definition pseudo-opcodes for TKGate. 



14.22 Microcode 

It follows the microcode listing, describing the opcode procedures. 
Listing 14.61. Microcode for TKGate. 

begin microcode @ 0 

// 

fetch: 

// IR <- M[PC++], load 

M=rank8 M=byteO M=code M=ram_oe M=ir_load PCi=l CTRL=load; 

nop: 

// Just jump to the fetch microcode: 

ADDR=fetch JUMP=unconditional; 

st_a_b: 

Ar=enable Br=load ADDR=fetch JUMP=unconditional; 

st_a_c: 

Ar=enable Cr=load ADDR=fetch JUMP=unconditional; 

st_a_d: 




1160 


Version "F": 32-bit registers, big-endian, privileges 



Ar=enable 

Dr=load 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_a_i : 





Ar=enable 

Ir=load 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_a_j : 





Ar=enable 

Jr=load 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_a_sp: 





Ar=enable 

SPr=load 

ADDR=fetch 

JUMP unconditional; 

st_ 

i 

o 

1 

l-h 





Ar=enable 

FPr=load 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_b_a: 





Br=enable 

Armload 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_b_c: 





Br=enable 

Cr=load 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_b_d: 





Br=enable 

Dr=load 

ADDR=fetch 

JUMP unconditional; 

st_ 

_b_i : 





Br=enable 

Ir=load 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_b_j : 





Br=enable 

Jr=load 

ADDR=fetch 

JUMP=unconditional; 

st_ 

_b_sp: 





Br=enable 

SPr=load 

ADDR=fetch 

JUMP unconditional; 

st_ 

_b_f p: 





Br=enable 

FPr=load 

ADDR=fetch 

JUMP=unconditional; 

ld_ 

_a_b: 





Br=enable 

Ar=load 

ADDR=fetch 

JUMP=unconditional; 

ld_ 

_a_c: 





Cr=enable 

Armload 

ADDR=fetch 

JUMP unconditional; 

Id. 

_a_d: 





Dr=enable 

Armload 

ADDR=fetch 

JUMP=unconditional; 

ld_ 

_a_i : 





Ir=enable 

Armload 

ADDR=fetch 

JUMP unconditional; 

ld_ 

- a —j : 





Jr=enable 

Armload 

ADDR=fetch 

JUMP=unconditional; 

ld_ 

_a_sp: 





SPr=enable 

Ar=load 

ADDR=fetch 

JUMP=unconditional; 

ld_ 

i 

o 

1 

l-h 

*3 





FPr=enable 

Armload 

ADDR=fetch 

JUMP=unconditional; 

ld_ 

_b_a: 





Br=enable 

Br=load 

ADDR=fetch 

JUMP=unconditional; 

ld_ 

_b_c: 







Version "F": 32-bit registers, big-endian, privileges 


1161 


Cr=enable Br=load 
1d_b_d: 

Dr=enable Br=load 
ld_b_i : 

Ir=enable Br=load 
ld_b_j : 

Jr=enable Br=load 
ld_b_sp: 

SPr=enable Br=load 


ADDR=fetch JUMP unconditional; 
ADDR=fetch JUMP unconditional; 
ADDR=fetch JUMP=unconditional; 
ADDR=fetch JUMP=unconditional; 
ADDR=fetch JUMP=unconditional; 


ld_b_fp: 

FPr=enable Br=load 
ld8ur_i: 

DA=i M=rank8 M=byteO M=data 
Armload 

ld8ur_j: 

DA=j M=rank8 M=byteO M=data 
Ar=load 
ld8ur_sp: 

DA=sp M=rank8 M=byteO M=data 
Armload 
ld8ur_fp: 

DA=fp M=rank8 M=byteO M=data 
Armload 

ld8sr_i: 

DA=i M=rank8 M=byteO M=data 
Armload 

ld8sr_j: 

DA=j M=rank8 M=byteO M=data 
Armload 
ld8sr_sp: 

DA=sp M=rank8 M=byteO M=data 
Armload 
ld8sr_fp: 

DA=fp M=rank8 M=byteO M=data 
Armload 

ld8u: 

M=rank8 M=byteO M=code M=ram_ 
Armload PCi=l 


ADDR=fetch JUMP unconditional; 

M=ram_oe M=unsigned M=md_enable 

ADDR=fetch JUMP=unconditional; 

M=ram_oe M=unsigned M=md_enab1e 

ADDR=fetch JUMP=unconditional; 

M=ram_oe M=unsigned M=md_enable 

ADDR=fetch JUMP unconditional; 

M=ram_oe M=unsigned M=md_enable 

ADDR=fetch JUMP=unconditional; 

M=ram_oe M=signed M=md_enable 

ADDR=fetch JUMP unconditional; 

M=ram_oe M=signed M=md_enable 

ADDR=fetch JUMP unconditional; 

M=ram_oe M=signed M=md_enable 

ADDR=fetch JUMP=unconditional; 

M=ram_oe M=signed M=md_enable 

ADDR=fetch JUMP unconditional; 

oe M=unsigned M=md_enable 

ADDR=fetch JUMP unconditional; 


ld8s : 

M=rank8 M=byteO M=code M=ram_oe M=signed M=md_enable 




1162 


Version "F": 32-bit registers, big-endian, privileges 


Ar=load PCi=l ADDR=fetch JUMP=unconditional; 

ldl6ur_i: 

DA=i M=rankl6 M=bytel M=data M=ram_oe; 

DA=i M=rankl6 M=byteO M=data M=ram_oe M=md_enable M=unsigned 

Armload ADDR=fetch JUMP unconditional; 

ldl6ur_j: 

DA=j M=rankl6 M=bytel M=data M=ram_oe; 

DA=j M=rankl6 M=byteO M=data M=ram_oe M=md_enable M=unsigned 

Armload ADDR=fetch JUMP unconditional; 

ldl6ur_sp: 

DA=sp M=rankl6 M=bytel M=data M=ram_oe; 

DA=sp M=rankl6 M=byteO M=data M=ram_oe M=md_enable M=unsigned 

Armload ADDR=fetch JUMP=unconditional; 

ldl6ur_fp: 

DA=fp M=rankl6 M=bytel M=data M=ram_oe; 

DA=fp M=rankl6 M=byteO M=data M=ram_oe M=md_enab1e M=unsigned 

Ar=load ADDR=fetch JUMP=unconditional; 

ldl6sr_i: 

DA=i M=rankl6 M=bytel M=data M=ram_oe; 

DA=i M=rankl6 M=byteO M=data M=ram_oe M=md_enable M=signed 

Ar=load ADDR=fetch JUMP=unconditional; 

ldl6sr_j: 

DA=j M=rankl6 M=bytel M=data M=ram_oe; 

DA= j M=rankl6 M=byteO M=data M=ram_oe M=md_enable M=signed 

Armload ADDR=fetch JUMP=unconditional; 

ldl6sr_sp: 

DA=sp M=rankl6 M=bytel M=data M=ram_oe; 

DA=sp M=rankl6 M=byteO M=data M=ram_oe M=md_enable M=signed 

Armload ADDR=fetch JUMP=unconditional; 

ldl6sr_fp: 

DA=fp M=rankl6 M=bytel M=data M=ram_oe; 

DA=fp M=rankl6 M=byteO M=data M=ram_oe M=md_enable M=signed 

Ar=load ADDR=fetch JUMP=unconditional; 

ldl6u: 

M=rankl6 M=bytel M=code M=ram_oe; 

M=rankl6 M=byteO M=code M=ram_oe M=md_enable M=unsigned Armload 
PCi=2 ADDR=fetch JUMP=unconditional; 

ldl6s : 

M=rankl6 M=bytel M=code M=ram_oe; 

M=rankl6 M=byteO M=code M=ram_oe M=md_enable M=signed 


Armload 




Version "F": 32-bit registers, big-endian, privileges 


1163 


PCi : 

=2 



ld24ur_i: 




DA=i 

M=rank24 

M=byte2 

M=data 

DA=i 

M=rank24 

M=bytel 

M=data 

DA=i 

M=rank24 

M=byteO 

M=data 

Ar= 

load 



ld24ur_j: 




DA= j 

M=rank24 

M=byte2 

M=data 

DA= j 

M=rank24 

M=bytel 

M=data 

DA= j 

M=rank24 

M=byteO 

M=data 

Ar= 

load 



ld24ur_sp 

: 



DA=sp 

M=rank24 

M=byte2 

M=data 

DA=sp 

M=rank24 

M=bytel 

M=data 

DA=sp 

M=rank24 

M=byteO 

M=data 

Ar= 

load 



ld24ur_fp 

: 



DA=fp 

M=rank24 

M=byte2 

M=data 

DA=fp 

M=rank24 

M=bytel 

M=data 

DA=fp 

M=rank24 

M=byteO 

M=data 

Ar= 

load 



ld24sr_i: 




DA=i 

M=rank24 

M=byte2 

M=data 

DA=i 

M=rank24 

M=bytel 

M=data 

DA=i 

M=rank24 

M=byteO 

M=data 

Ar= 

load 



ld24sr_j: 




DA= j 

M=rank24 

M=byte2 

M=data 

DA= j 

M=rank24 

M=bytel 

M=data 

DA= j 

M=rank24 

M=byteO 

M=data 

Ar= 

load 



ld24sr_sp 

: 



DA=sp 

M=rank24 

M=byte2 

M=data 

DA=sp 

M=rank24 

M=bytel 

M=data 

DA=sp 

M=rank24 

M=byteO 

M=data 

Ar= 

load 



ld24sr_fp 

: 



DA=fp 

M=rank24 

M=byte2 

M=data 

DA=fp 

M=rank24 

M=bytel 

M=data 

DA=fp 

M=rank24 

M=byteO 

M=data 


ADDR=fetch JUMP=unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=unsigned 

ADDR=fetch JUMP unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=unsigned 

ADDR=fetch JUMP unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=unsigned 

ADDR=fetch JUMP=unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=unsigned 

ADDR=fetch JUMP unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=signed 

ADDR=fetch JUMP=unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=signed 

ADDR=fetch JUMP=unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=signed 

ADDR=fetch JUMP=unconditional; 

M=ram_oe; 

M=ram_oe; 

M=ram_oe M=md_enable M=signed 




104 


Version "F": 32-bit registers, big-endian, privileges 


Ar=load ADDR=fetch JUMP=unconditional; 

ld24u: 

M=rank24 M=byte2 M=code M=ram_oe; 

M=rank24 M=bytel M=code M=ram_oe; 

M=rank24 M=byteO M=code M=ram_oe M=md_enable M=unsigned 

Armload PCi=3 ADDR=fetch JUMP=unconditional; 

ld24s : 

M=rank24 M=byte2 M=code M=ram_oe; 

M=rank24 M=bytel M=code M=ram_oe; 

M=rank24 M=byteO M=code M=ram_oe M=md_enable M=signed 

Armload PCi=3 ADDR=fetch JUMP=unconditional; 

ld32u: 

M=rank32 M=byte3 M=code M=ram_oe; 

M=rank32 M=byte2 M=code M=ram_oe; 

M=rank32 M=bytel M=code M=ram_oe; 

M=rank32 M=byteO M=code M=ram_oe M=md_enable M=unsigned 

Ar=load PCi=4 ADDR=fetch JUMP=unconditional; 

ld32s : 

M=rank32 M=byte3 M=code M=ram_oe; 

M=rank32 M=byte2 M=code M=ram_oe; 

M=rank32 M=bytel M=code M=ram_oe; 

M=rank32 M=byteO M=code M=ram_oe M=md_enab1e M=signed 

Armload PCi=4 ADDR=fetch JUMP=unconditional; 

ld32ur_i: 

DA=i M=rank32 M=byte3 M=data M=ram_oe; 

DA=i M=rank32 M=byte2 M=data M=ram_oe; 

DA=i M=rank32 M=bytel M=data M=ram_oe; 

DA=i M=rank32 M=byteO M=data M=ram_oe M=md_enable M=unsigned 

Ar=load ADDR=fetch JUMP=unconditional; 

ld32ur_j: 

DA=j M=rank32 M=byte3 M=data M=ram_oe; 

DA=j M=rank32 M=byte2 M=data M=ram_oe; 

DA=j M=rank32 M=bytel M=data M=ram_oe; 

DA=j M=rank32 M=byteO M=data M=ram_oe M=md_enable M=unsigned 

Armload ADDR=fetch JUMP=unconditional; 

ld32ur_sp: 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable M=unsigned 




Version "F": 32-bit registers, big-endian, privileges 


1165 


Ar=load ADDR=fetch JUMP=unconditional; 

ld32ur_fp: 

DA=fp M=rank32 M=byte3 M=data M=ram_oe; 

DA=fp M=rank32 M=byte2 M=data M=ram_oe; 

DA=fp M=rank32 M=bytel M=data M=ram_oe; 

DA=fp M=rank32 M=byteO M=data M=ram_oe M=md_enable M=unsigned 

Armload ADDR=fetch JUMP unconditional; 

ld32sr_i: 

DA=i M=rank32 M=byte3 M=data M=ram_oe; 

DA=i M=rank32 M=byte2 M=data M=ram_oe; 

DA=i M=rank32 M=bytel M=data M=ram_oe; 

DA=i M=rank32 M=byteO M=data M=ram_oe M=md_enable M=signed 

Ar=load ADDR=fetch JUMP unconditional; 

ld32sr_j: 

DA=j M=rank32 M=byte3 M=data M=ram_oe; 

DA=j M=rank32 M=byte2 M=data M=ram_oe; 

DA=j M=rank32 M=bytel M=data M=ram_oe; 

DA=j M=rank32 M=byteO M=data M=ram_oe M=md_enable M=signed 

Ar=load ADDR=fetch JUMP unconditional; 

ld32sr_sp: 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable M=signed 

Ar=load ADDR=fetch JUMP unconditional; 

ld32sr_fp: 

DA=fp M=rank32 M=byte3 M=data M=ram_oe; 

DA=fp M=rank32 M=byte2 M=data M=ram_oe; 

DA=fp M=rank32 M=bytel M=data M=ram_oe; 

DA=fp M=rank32 M=byteO M=data M=ram_oe M=md_enable M=signed 

Ar=load ADDR=fetch JUMP unconditional; 

lea_a_i: 

DA=i DA=enable Armload; ADDR=fetch JUMP=unconditional; 

lea_a_j: 

DA=j DA=enable Armload ADDR=fetch JUMP=unconditional; 

lea_a_sp: 

DA=sp DA=enable Armload ADDR=fetch JUMP=unconditional; 

lea_a_fp: 

DA=fp DA=enable Ar=load 
lea_b_i: 


ADDR=fetch JUMP=unconditional; 




1166 


Version "F": 32-bit registers, big-endian, privileges 


DA=i DA=enable Br=load 

ADDR=fetch 

JUMP=unconditional; 

lea_b_j: 




DA=j DA=enable Br=load 

ADDR=fetch 

JUMP unconditional; 

lea_b_sp: 




DA=sp DA=enable Br=load 

ADDR=fetch 

JUMP=unconditional; 

lea_b_fp: 




DA=fp DA=enable Br=load 

ADDR=fetch 

JUMP=unconditional; 

swap_a_a: 


ADDR=fetch 

JUMP unconditional; 

swap_b_b: 


ADDR=fetch 

JUMP=unconditional; 

swap_b_a: 




Ar=enable 

TMP0=load; 



Br=enable 

Armload; 



TMPO=enable 

Br=load 

ADDR=fetch 

JUMP unconditional; 

swap_a_b: 




Ar=enable 

TMP0=load; 



Br=enable 

Ar=load; 



TMPO=enable 

Br=load 

ADDR=fetch 

JUMP=unconditional; 

swap_a_c: 




Ar=enable 

TMP0=load; 



Cr=enable 

Armload; 



TMPO=enable 

Cr=load 

ADDR=fetch 

JUMP=unconditional; 

swap_a_d: 




Ar=enable 

TMP0=load; 



Dr=enable 

Armload; 



TMPO=enable 

Dr=load 

ADDR=fetch 

JUMP unconditional; 

swap_a_i: 




Ar=enable 

TMP0=load; 



Ir=enable 

Ar=load; 



TMPO=enable 

Ir=load 

ADDR=fetch 

JUMP=unconditional; 

swap_a_j: 




Ar=enable 

TMP0=load; 



Jr=enable 

Ar=load; 



TMPO=enable 

Jr=load 

ADDR=fetch 

JUMP unconditional; 

swap_a_sp: 




Ar=enable 

TMP0=load; 



SPr=enable 

Ar=load; 



TMPO=enable 

SPr=load 

ADDR=fetch 

JUMP=unconditional; 

swap_a_fp: 







Version "F": 32-bit registers, big-endian, privileges 


1167 


Ar=enable 

TMP0=load; 




FPr=enable 

Armload; 




TMPO=enable 

FPr=load 


ADDR=fetch 

JUMP unconditional; 

swap_b_c: 





Br=enable 

TMP0=load; 




Cr=enable 

Br=load; 




TMPO=enable 

Cr=load 


ADDR=fetch 

JUMP unconditional; 

swap_b_d: 





Br=enable 

TMP0=load; 




Dr=enable 

Br=load; 




TMPO=enable 

Dr=load 


ADDR=fetch 

JUMP unconditional; 

swap_b_i: 





Br=enable 

TMP0=load; 




Ir=enable 

Br=load; 




TMPO=enable 

Ir=load 


ADDR=fetch 

JUMP=unconditional; 

swap_b_j: 





Br=enable 

TMP0=load; 




Jr=enable 

Br=load; 




TMPO=enable 

Jr=load 


ADDR=fetch 

JUMP=unconditional; 

swap_b_sp: 





Br=enable 

TMP0=load; 




SPr=enable 

Br=load; 




TMPO=enable 

SPr=load 


ADDR=fetch 

JUMP unconditional; 

swap_b_fp: 





Br=enable 

TMP0=load; 




FPr=enable 

Br=load; 




TMPO=enable 

FPr=load 


ADDR=fetch 

JUMP unconditional; 

st8r_i: 





Ar=enable DA= 

=i M=rank8 

M=byteO 

M=data M=ram_we 




ADDR=fetch 

JUMP=unconditional; 

st8r_j: 





Ar=enable DA= 

=j M=rank8 

M=byteO 

M=data M=ram_we 




ADDR=fetch 

JUMP=unconditional; 

st8r_sp: 





Ar=enable DA= 

= sp M=rank8 

M=byteO 

M=data M=ram_we 




ADDR=fetch 

JUMP unconditional; 

st8r_fp: 





Ar=enable DA= 

=fp M=rank8 

M=byteO 

M=data M=ram_we 




1168 


Version "F": 32-bit registers, big-endian, privileges 






ADDR=fetch JUMP=unconditional; 

stl6r_i: 

Ar=enable 

DA=i 

M=rankl6 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA=i 

M=rankl6 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP=unconditional; 

st16r_j: 

Ar=enable 

DA= j 

M=rankl6 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA= j 

M=rankl6 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP unconditional; 

st16r_sp: 

Ar=enable 

DA=sp 

M=rankl6 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA=sp 

M=rankl6 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP=unconditional; 

st16r_fp: 

Ar=enable 

DA=fp 

M=rankl6 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA=fp 

M=rankl6 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP unconditional; 

st24r_i: 

Ar=enable 

DA=i 

M=rank24 

M=byte2 

M=data M=ram_we; 

Ar=enable 

DA=i 

M=rank24 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA=i 

M=rank24 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP unconditional; 

st24r_j: 

Ar=enable 

DA= j 

M=rank24 

M=byte2 

M=data M=ram_we; 

Ar=enable 

DA= j 

M=rank24 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA= j 

M=rank24 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP unconditional; 

st24r_sp: 

Ar=enable 

DA=sp 

M=rank24 

M=byte2 

M=data M=ram_we; 

Ar=enable 

DA=sp 

M=rank24 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA=sp 

M=rank24 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP=unconditional; 

st24r_fp: 

Ar=enable 

DA=fp 

M=rank24 

M=byte2 

M=data M=ram_we; 

Ar=enable 

DA=fp 

M=rank24 

M=bytel 

M=data M=ram_we; 

Ar=enable 

DA=fp 

M=rank24 

M=byteO 

M=data M=ram_we 

ADDR=fetch JUMP=unconditional; 

st32r_i: 

Ar=enable 

DA=i 

M=rank32 

M=byte3 

M=data M=ram_we; 

Ar=enable 

DA=i 

M=rank32 

M=byte2 

M=data M=ram_we; 




Version "F": 32-bit registers, big-endian, privileges 


1169 


Ar=enable 

DA=i 

M=rank32 

M=bytel 

M=data 

M=ram_we; 

Ar=enable 

DA=i 

M=rank32 

M=byte0 

M=data 

M=ram_we 





ADDR=fetch JUMP=unconditional; 

st32r_j: 






Ar=enable 

DA= j 

M=rank32 

M=byte3 

M=data 

M=ram_we; 

Ar=enable 

DA= j 

M=rank32 

M=byte2 

M=data 

M=ram_we; 

Ar=enable 

DA= j 

M=rank32 

M=bytel 

M=data 

M=ram_we; 

Ar=enable 

DA= j 

M=rank32 

M=byte0 

M=data 

M=ram_we 





ADDR=fetch JUMP unconditional; 

st32r_sp: 






Ar=enable 

DA=sp 

M=rank32 

M=byte3 

M=data 

M=ram_we; 

Ar=enable 

DA=sp 

M=rank32 

M=byte2 

M=data 

M=ram_we; 

Ar=enable 

DA=sp 

M=rank32 

M=bytel 

M=data 

M=ram_we; 

Ar=enable 

DA=sp 

M=rank32 

M=byte0 

M=data 

M=ram_we 





ADDR=fetch JUMP=unconditional; 

st32r_fp: 






Ar=enable 

DA=fp 

M=rank32 

M=byte3 

M=data 

M=ram_we; 

Ar=enable 

DA=fp 

M=rank32 

M=byte2 

M=data 

M=ram_we; 

Ar=enable 

DA=fp 

M=rank32 

M=bytel 

M=data 

M=ram_we; 

Ar=enable 

DA=fp 

M=rank32 

M=byte0 

M=data 

M=ram_we 





ADDR=fetch JUMP=unconditional; 

push_a: 






Jr=enable 

TMP 0 = 

load; 

// %J is saved and later restored. 

CNSv=0x0 0 

CNS=enable Jr=. 

load SPi= 

=-4; 


Ar=enable 

DA=sp 

M=rank32 

M=byte3 

M=data 

M=ram_we; 

Ar=enable 

DA=sp 

M=rank32 

M=byte2 

M=data 

M=ram_we; 

Ar=enable 

DA=sp 

M=rank32 

M=bytel 

M=data 

M=ram_we; 

Ar=enable 

DA=sp 

M=rank32 

M=byte0 

M=data 

M=ram_we; 

TMPO=enable Jr= 

load 


ADDR=fetch JUMP=unconditional; 

push_b: 






Jr=enable 

TMP0 = 

load; 

// %J is saved and later restored. 

CNSv=0 CNS=enable Jr=load SPi=-4; 



Br=enable 

DA=sp 

M=rank32 

M=byte3 

M=data 

M=ram_we; 

Br=enable 

DA=sp 

M=rank32 

M=byte2 

M=data 

M=ram_we; 

Br=enable 

DA=sp 

M=rank32 

M=bytel 

M=data 

M=ram_we; 

Br=enable 

DA=sp 

M=rank32 

M=byte0 

M=data 

M=ram_we; 

TMPO=enable Jr= 

load 


ADDR=fetch JUMP=unconditional; 

push_c: 






Jr=enable 

TMP0 = 

load; 

// %J is saved and later restored. 

CNSv=0 CNS=enable Jr=load SPi=-4; 





1170 


Version "F": 32-bit registers, big-endian, privileges 


Cr=enable DA=sp M=rank32 M=byte3 M=data M=ram_we; 

Cr=enable DA=sp M=rank32 M=byte2 M=data M=ram_we; 

Cr=enable DA=sp M=rank32 M=bytel M=data M=ram_we; 

Cr=enable DA=sp M=rank32 M=byte0 M=data M=ram_we; 

TMP0=enable Jr=load ADDR=fetch JUMP=unconditional; 

push_d: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0 CNS=enable Jr=load SPi=-4; 

Dr=enable DA=sp M=rank32 M=byte3 M=data M=ram_we; 

Dr=enable DA=sp M=rank32 M=byte2 M=data M=ram_we; 

Dr=enable DA=sp M=rank32 M=bytel M=data M=ram_we; 

Dr=enable DA=sp M=rank32 M=byte0 M=data M=ram_we; 

TMP0=enable Jr=load ADDR=fetch JUMP=unconditional; 

push_i: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0 CNS=enable Jr=load SPi=-4; 

Ir=enable DA=sp M=rank32 M=byte3 M=data M=ram_we; 

Ir=enable DA=sp M=rank32 M=byte2 M=data M=ram_we; 

Ir=enable DA=sp M=rank32 M=bytel M=data M=ram_we; 

Ir=enable DA=sp M=rank32 M=byte0 M=data M=ram_we; 

TMP0=enable Jr=load ADDR=fetch JUMP=unconditional; 

push_j: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0 CNS=enable Jr=load SPi=-4; 

TMP0=enable DA=sp M=rank32 M=byte3 M=data M=ram_we; 

TMP0=enable DA=sp M=rank32 M=byte2 M=data M=ram_we; 

TMP0=enable DA=sp M=rank32 M=bytel M=data M=ram_we; 

TMP0=enable DA=sp M=rank32 M=byte0 M=data M=ram_we; 

TMP0=enable Jr=load ADDR=fetch JUMP=unconditional; 

push_sp: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=-4 CNS=enable Jr=load; 

SPr=enable TMPl=load SPi=-4; 

TMPl=enable DA=sp M=rank32 M=byte3 M=data M=ram_we; 

TMPl=enable DA=sp M=rank32 M=byte2 M=data M=ram_we; 

TMPl=enable DA=sp M=rank32 M=bytel M=data M=ram_we; 

TMPl=enable DA=sp M=rank32 M=byte0 M=data M=ram_we; 

TMP0=enable Jr=load ADDR=fetch JUMP=unconditional; 

push_fp: 

Jr=enable TMP0=load; // %J is saved and later restored . 



Version "F": 32-bit registers, big-endian, privileges 


1171 


CNSv=0 CNS=enable Jr=load SPi=-4; 

FPr=enable DA=sp M=rank32 M=byte3 M=data M=ram_we; 

FPr=enable DA=sp M=rank32 M=byte2 M=data M=ram_we; 

FPr=enable DA=sp M=rank32 M=bytel M=data M=ram_we; 

FPr=enable DA=sp M=rank32 M=byteO M=data M=ram_we; 

TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

pop_a: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable Armload SPi=4; 
TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

pop_b: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable Br=load SPi=4; 

TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

pop_c: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable Cr=load SPi=4; 

TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

pop_d: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable Dr=load SPi=4; 

TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

pop_i: 

Jr=enable TMP0=load; // %J is saved and later restored . 



1172 


Version "F": 32-bit registers, big-endian, privileges 


CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable Ir=load SPi=4; 
TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

pop_j: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable Jr=load SPi=4 

ADDR=fetch JUMP=unconditional; 

pop_sp: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable SPr=load; 
TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

pop_fp: 

Jr=enable TMP0=load; // %J is saved and later restored . 

CNSv=0x00 CNS=enable Jr=load; 

DA=sp M=rank32 M=byte3 M=data M=ram_oe; 

DA=sp M=rank32 M=byte2 M=data M=ram_oe; 

DA=sp M=rank32 M=bytel M=data M=ram_oe; 

DA=sp M=rank32 M=byteO M=data M=ram_oe M=md_enable FPr=load SPi=4; 
TMPO=enable Jr=load ADDR=fetch JUMP=unconditional; 

equal8s: 

ALU=rank8 ALU=equal ALU=signed FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP=unconditional; 

equall6s: 

ALU=rankl6 ALU=equal ALU=signed FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

equal24s: 

ALU=rank24 ALU=equal ALU=signed FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP=unconditional; 

equa!32s: 



Version "F": 32-bit registers, big-endian, privileges 


1173 


ALU=rank32 ALU=equal ALU=signed 
not8s : 

ALU=rank8 ALU=not ALU=signed 

not16s : 

ALU=rankl6 ALU=not ALU=signed 
not24s: 

ALU=rank24 ALU=not ALU=signed 
not32s : 

ALU=rank32 ALU=not ALU=signed 
and8s: 

ALU=rank8 ALU=and ALU=signed 

andl6s: 

ALU=rankl6 ALU=and ALU=signed 
and24s: 

ALU=rank24 ALU=and ALU=signed 
and32s: 

ALU=rank32 ALU=and ALU=signed 
nand8s: 

ALU=rank8 ALU=nand ALU=signed 
nandl6s: 

ALU=rankl6 ALU=nand ALU=signed 
nand24s: 

ALU=rank24 ALU=nand ALU=signed 
nand32s: 

ALU=rank32 ALU=nand ALU=signed 
or8s : 

ALU=rank8 ALU=or ALU=signed 


FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 




1174 


Version "F": 32-bit registers, big-endian, privileges 


orl6s: 

ALU=rankl6 ALU=or ALU=signed 

or24s: 

ALU=rank24 ALU=or ALU=signed 

or32s: 

ALU=rank32 ALU=or ALU=signed 

nor8s: 

ALU=rank8 ALU=nor ALU=signed 

nor16s: 

ALU=rankl6 ALU=nor ALU=signed 
nor24s: 

ALU=rank24 ALU=nor ALU=signed 
nor32s: 

ALU=rank32 ALU=nor ALU=signed 
xor8s: 

ALU=rank8 ALU=xor ALU=signed 

xor16s: 

ALU=rankl6 ALU=xor ALU=signed 

xor24s: 

ALU=rank24 ALU=xor ALU=signed 
xor32s: 

ALU=rank32 ALU=xor ALU=signed 
nxor8s: 

ALU=rank8 ALU=nxor ALU=signed 

nxor16s: 

ALU=rankl6 ALU=nxor ALU=signed 


ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 




Version "F": 32-bit registers, big-endian, privileges 


1175 


nxor24s: 

ALU=rank24 ALU=nxor ALU=signed 
nxor32s: 

ALU=rank32 ALU=nxor ALU=signed 
add8s: 

ALU=rank8 ALU=add ALU=signed 
addl6s: 

ALU=rankl6 ALU=add ALU=signed 
add24s: 

ALU=rank24 ALU=add ALU=signed 
add32s: 

ALU=rank32 ALU=add ALU=signed 
sub8s: 

ALU=rank8 ALU=sub ALU=signed 
subl6s: 

ALU=rankl6 ALU=sub ALU=signed 
sub24s : 

ALU=rank24 ALU=sub ALU=signed 
sub32s : 

ALU=rank32 ALU=sub ALU=signed 
addc8s: 

ALU=rank8 ALU=addc ALU=signed 
addcl6s: 

ALU=rankl6 ALU=addc ALU=signed 
addc24s: 

ALU=rank24 ALU=addc ALU=signed 


FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP unconditional; 


addc32s: 




1176 


Version "F": 32-bit registers, big-endian, privileges 


ALU=rank32 ALU=addc ALU=signed 
subb8s: 

ALU=rank8 ALU=subb ALU=signed 
subbl6s: 

ALU=rankl6 ALU=subb ALU=signed 
subb2 4s : 

ALU=rank24 ALU=subb ALU=signed 
subb32s: 

ALU=rank32 ALU=subb ALU=signed 
lshl8s: 

ALU=rank8 ALU=lshl ALU=signed 
lshll6s: 

ALU=rankl6 ALU=lshl ALU=signed 
lshl24s: 

ALU=rank24 ALU=lshl ALU=signed 
lshl32s: 

ALU=rank32 ALU=lshl ALU=signed 
lshr8s: 

ALU=rank8 ALU=lshr ALU=signed 
lshrl6s : 

ALU=rankl6 ALU=lshr ALU=signed 
lshr24s: 

ALU=rank24 ALU=lshr ALU=signed 
lshr32s: 

ALU=rank32 ALU=lshr ALU=signed 
ashl8s: 

ALU=rank8 ALU=ashl ALU=signed 


FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Ar=load 

ADDR=fetch JUMP=unconditional; 

FL=load_alu ALU=enable Armload